
package Sintactico;

import Activacion.Display;
import Activacion.RegActivacion;
import java.util.ArrayList;
import Enumerados.*;
import Lexico.Token;
import Tabla.CampoReg;
import Tabla.DescTipo;
import Tabla.DescTipo.tipo;
import Tabla.EntradaTabla;
import Tabla.EntradaTabla.Clase;
import Tabla.Param;
import Tabla.Param.Modo;
import Tabla.TablaApilada;
import Tabla.TablaSimbolos;
import Tabla.TablaSimbolosGlobal;
import Tabla.TipoArray;
import Tabla.TipoBasico;
import Tabla.TipoRef;
import Tabla.TipoFun;
import Tabla.TipoPuntero;
import Tabla.TipoRegistro;

/**
 *
 * @author
 *
 * Almaraz HernÃ¡ndez, JesÃºs
 * BÃ©cares GarcÃ­a, Javier
 * Calzada MartÃ­nez, JesÃºs
 * Campos Cantero, Pablo
 * GÃ³mez Galindo, Alejandro
 * Ortiz SÃ¡nchez, Enrique
 *
 *
 */


public class AnalizadorSintactico {

    private ArrayList<Token> tokens;
    private ArrayList codigo;
    private ArrayList errores;
    private ArrayList ambigua;
    private TablaSimbolosGlobal tablaGlobal;
    private Display display;
    private RegActivacion regActivacion;
    private boolean errorP;
    private int tokenActual;
    private int etiqueta;
    private int linea;
    private int columna;
    private static enum tipoAtributoS {ENT,REAL,LOG,TERR};
    private boolean error;
    private int dir;
    private int nivel;
    private TablaApilada ambitoActual;
    boolean errorDec=false;
    boolean errorAcc=false;
   

    public AnalizadorSintactico(ArrayList<Token> tokens){
        this.tokens=tokens;
        this.codigo=new ArrayList();
        this.errores=new ArrayList();
        this.ambigua=new ArrayList();
        this.tablaGlobal=new TablaSimbolosGlobal();
        this.errorP=false;
        this.tokenActual=0;
        this.etiqueta=0;
        this.linea=1;
        this.columna=1;
        this.error=false;
        this.dir=0;
        this.nivel=0;
        display=Display.getInstance();
     }

    public ArrayList Inicio(){
        errorP=reconocePrograma();
        return codigo;
    }

    public String getErrores(){
          String s="";
            for(int i=0;i<errores.size();i++){
            s+=errores.get(i).toString()+"\n";
            }
            return s;
    }

    public ArrayList<EntradaTabla> getVariables(){
        return ambitoActual.getTdS().getVariables();

    }
 /******************************************************************************
 *                                                                             *
 *                   Prog ::= Decs  Accs                                       *
 *                                                                             *
 ******************************************************************************/
    private boolean reconocePrograma() {
        //Creamos la tabla del programa principal
        TablaSimbolos t=new TablaSimbolos();
        /*creamos una nueva tablaApilada que tendra su tabla padre a null,ya que al
        ser la tabla del programa principal no tiene tabla padre*/
        TablaApilada tabla=new TablaApilada(t);
        this.setAmbitoActual(tabla);
        regActivacion=new RegActivacion(ambitoActual.getTdS(),null,0);
        Decs(tabla,nivel);
        if(!errorDec && !ambitoActual.getTdS().hayTiposPendientes()){
            errorAcc=reconoceAcciones();
            codigo.add("STOP\n");
        }
        return (errorDec || errorAcc);

    }
    
 /******************************************************************************
 *                                                                             *
 *                   Decs ::= λ | RDecs                                        *
 *                                                                             *
 ******************************************************************************/
    private void Decs(TablaApilada tabla,int nivel){

        //La tabla de simbolos "se crea" en la constructora de la clase.
        //La direccion se inicializa en la constructora.

        Token token = dameToken();
        Enumerados.categoriaLexica cat = token.getCat();

        if(cat.equals(Enumerados.categoriaLexica.CLTENT) || cat.equals(Enumerados.categoriaLexica.CLTREAL) || cat.equals(Enumerados.categoriaLexica.CLTIPO) || cat.equals(Enumerados.categoriaLexica.CLFUN)){

            RDecs(tabla,nivel);

        }
    }
    
 /******************************************************************************
 *                                                                             *
 *                   RDecs ::= Dec | RDecs                                     *
 *                                                                             *
 ******************************************************************************/
    private void RDecs(TablaApilada tabla,int nivel){
      Token token = dameToken();
        Enumerados.categoriaLexica cat = token.getCat();

        if(cat.equals(Enumerados.categoriaLexica.CLTENT) || cat.equals(Enumerados.categoriaLexica.CLTREAL) || cat.equals(Enumerados.categoriaLexica.CLTIPO) || cat.equals(Enumerados.categoriaLexica.CLFUN) || ((cat.equals(Enumerados.categoriaLexica.CLIDENT)) && (ambitoActual.getTdS().dameEntradaTabla(token.getLex()).getClase().equals(Clase.tipo))) ){
        Dec(tabla,nivel);
        RDecs(tabla,nivel);
        }
       
    }
    
/******************************************************************************
 *                                                                            *
 *                   Dec ::= DecVar | DecTipo | DecFun                        *
 *                                                                            *
 *****************************************************************************/
    private void Dec(TablaApilada tabla,int nivel){
        Token token = dameToken();
        Enumerados.categoriaLexica cat = token.getCat();

        if (cat.equals(Enumerados.categoriaLexica.CLTIPO)){
            DecTipo(tabla,nivel);
        }
        else if (cat.equals(Enumerados.categoriaLexica.CLFUN)){
            this.nivel=nivel++;
            DecFun(tabla,nivel);
        }
        else{
            DecVar(tabla,nivel);
        }
    }

    private void DecTipo(TablaApilada tabla,int nivel){
         Token token = avanzaYDameToken();
          Enumerados.categoriaLexica cat = token.getCat();
          EntradaTabla e;
          /*Comprobamos si el token tiene categoria lexica entero real o identificador,luego vemos si el token siguiente es un corchete
          para comprobar si es de tipo corchete abierto lo que indicaria que vamos a reconocer un array,o en caso contrario reconoceriamos una 
          declaracion de otro tipo */
          if (cat.equals(Enumerados.categoriaLexica.CLTENT) || cat.equals(Enumerados.categoriaLexica.CLTREAL) || cat.equals(Enumerados.categoriaLexica.CLIDENT)){
              token=(Token)tokens.get(tokenActual+1);
              cat=token.getCat();
              if (cat.equals(Enumerados.categoriaLexica.CLCORCHAB)){
                  token=dameToken();
                  cat=token.getCat();
                  TipoArray array=reconoceArray(token.getCat(),token.getLex());
                  if (array!=null){
                  e=new EntradaTabla(array.getNombre(),Clase.tipo,dir,array,0);                  
                  errorDec= (errorDec || !ambitoActual.getTdS().setIdentificador(e));
                  }                  
                  avanzaYDameToken();
                  columna=1;
            }
            else{
                  token = dameToken();
                  cat = token.getCat();
                  Enumerados.categoriaLexica tipoid=cat;
                  String idD=tokens.get(tokenActual+1).getLex();
                  if (cat.equals(Enumerados.categoriaLexica.CLTENT) || cat.equals(Enumerados.categoriaLexica.CLTREAL) || cat.equals(Enumerados.categoriaLexica.CLIDENT)){
                      String nombreTipo=token.getLex();
                      token = avanzaYDameToken();
                       cat = token.getCat();
                       if(cat.equals(Enumerados.categoriaLexica.CLIDENT)){
                           token = avanzaYDameToken();
                           cat = token.getCat();
                           
                           if(cat.equals(Enumerados.categoriaLexica.CLPYC)){
                                linea++;
                                DescTipo t;
                                if (tipoid.equals(Enumerados.categoriaLexica.CLTENT)){
                                     t=new TipoBasico(tipo.ENT,idD);
                                     e=new EntradaTabla(idD,Clase.tipo,dir,t,nivel);
                                     error = (errorDec || !ambitoActual.getTdS().setIdentificador(e));

                                }
                                else if (tipoid.equals(Enumerados.categoriaLexica.CLTREAL)){
                                     t=new TipoBasico(tipo.REAL,idD);
                                     e=new EntradaTabla(idD,Clase.tipo,dir,t,nivel);
                                     error = (errorDec || !ambitoActual.getTdS().setIdentificador(e));
                                }
                                else if (tipoid.equals(Enumerados.categoriaLexica.CLIDENT)){
                                     if(ambitoActual.getTdS().estaID(nombreTipo)){
                                         EntradaTabla entAux=ambitoActual.getTdS().dameEntradaTabla(nombreTipo);
                                         TipoRef tref=new TipoRef(nombreTipo,idD,entAux.getDesc());
                                         e=new EntradaTabla(idD,Clase.tipo,dir,tref,nivel);
                                        error = (errorDec || !ambitoActual.getTdS().setIdentificador(e));
                                     }
                                     else{
                                         columna-=2;
                                         errores.add("Error en la linea "+linea+" y columna "+columna+" porque el tipo no estaba declarado previamente");
                                         errorDec=true;
                                     }
                               }else{
                                    errores.add("Error en la linea "+linea+" y columna "+columna+" porque esperabamos un token de tipo CLTENT o CLTREAL o CLIDENT");
                                    errorDec=true;
                               }
                           }else{
                                errores.add("Error en la linea "+linea+" y columna "+columna+" porque esperabamos un token de tipo CLPYC");
                                errorDec=true;
                           }
                      }else{
                            errores.add("Error en la linea "+linea+" y columna "+columna+" porque esperabamos un token de tipo CLIDENT");
                            errorDec=true;
                      }
                  }else{
                      errores.add("Error en la linea "+linea+" y columna "+columna+" porque esperabamos un token de tipo CLTREAL o CLTENT o CLIDENT");
                      errorDec=true;
                  }
                  avanzaYDameToken();
                  columna=1;
              }


          }
          else if (cat.equals(Enumerados.categoriaLexica.CLREC)){
              linea++;
              e=reconoceRegistro();
              if (e!=null){
              errorDec=(errorDec || !ambitoActual.getTdS().setIdentificador(e));
              }
              avanzaYDameToken();
          }
          else if (cat.equals(Enumerados.categoriaLexica.CLPOINTER)){
              token = avanzaYDameToken();
              cat = token.getCat();
              String tipoApuntado=token.getLex();
              if (tokens.get(tokenActual+1).getCat().equals(Enumerados.categoriaLexica.CLCORCHAB)){
                         token=dameToken();
                         cat=token.getCat();
                         TipoArray array=reconoceArray(token.getCat(),token.getLex());
                          if (array!=null){
                          TipoPuntero punt=new TipoPuntero(array.getTbase().getNombre(),array,array.getNombre());
                          e=new EntradaTabla(array.getNombre(),Clase.tipo,dir,punt,0);
                          errorDec= (errorDec || !ambitoActual.getTdS().setIdentificador(e));
                  }
                  avanzaYDameToken();
                  columna=1;}
              else if(cat.equals(Enumerados.categoriaLexica.CLTENT) || cat.equals(Enumerados.categoriaLexica.CLTREAL) || cat.equals(Enumerados.categoriaLexica.CLIDENT))
                  {
                  token = avanzaYDameToken();
                  cat = token.getCat();
                  
                  if (cat.equals(Enumerados.categoriaLexica.CLIDENT)){
                       String nomPuntero=token.getLex();
                       token = avanzaYDameToken();
                       cat = token.getCat();
                       if (cat.equals(Enumerados.categoriaLexica.CLPYC)){
                           avanzaYDameToken();
                           linea++;
                           columna=1;

                           if(!ambitoActual.getTdS().estaID(tipoApuntado)&&!tipoApuntado.equals("int") && !tipoApuntado.equals("real")){
                               e=new EntradaTabla(nomPuntero,Clase.tipo,dir,null,0);
                               ambitoActual.getTdS().setIdentificador(e);
                               ambitoActual.getTdS().añadeTipoPendiente(tipoApuntado,nomPuntero);
                              
                           }
                           else if (tipoApuntado.equals("int")){
                                TipoBasico tbas=new TipoBasico(tipo.ENT,"ENT");
                                TipoPuntero punt=new TipoPuntero(nomPuntero,tbas,nomPuntero);
                                e=new EntradaTabla(nomPuntero,Clase.tipo,dir,punt,0);
                                ambitoActual.getTdS().setIdentificador(e);
                                
                           }
                           else if (tipoApuntado.equals("real")){
                                 TipoBasico tbas=new TipoBasico(tipo.REAL,"REAL");
                                TipoPuntero punt=new TipoPuntero(nomPuntero,tbas,nomPuntero);
                                e=new EntradaTabla(nomPuntero,Clase.tipo,dir,punt,0);
                                ambitoActual.getTdS().setIdentificador(e);
                               
                           }
                           else if (ambitoActual.getTdS().estaID(tipoApuntado)){
                                e = ambitoActual.getTdS().dameEntradaTabla(tipoApuntado);
                                TipoPuntero punt=new TipoPuntero(nomPuntero,e.getDesc(),nomPuntero);
                                e=new EntradaTabla(nomPuntero,Clase.tipo,dir,punt,0);
                                ambitoActual.getTdS().setIdentificador(e);
                               
                           }
                       }
                  }
              }
           }else{
                errores.add("Error en la linea "+linea+" y columna "+columna+" porque se esperaba un token de tipo puntero o registro o tipo basico");
                errorDec=true;   
           }
      
    }
    /*Reconocimiento de una funcion,llegamos aqui despues de reconocer un token de tipo CLFUN,reconocemos los parametros de la funcion y su modo
     * ya sea por valor o por variable,despues creamos una nueva entrada de la tabla de simbolos y guardamos en la tabla de simbolos del ambito actual
     * dicha entrada.Despues de esto necesitamos crearnos una nueva Tabla Apilada que tendra como tabla padre la tabla de simolos actual y como 
     * tabla propia una nueva que sera donde se almacenen todas las variables de la funcion.Una vez hecho esto,cambiamos el ambito a la nueva Tabla Apilada 
     * que hemos creado y volvemos a llamar a Decs(nuevaTabla) y a reconoceAcciones().
     */
    private void DecFun(TablaApilada tabla,int nivel){
        Token token=avanzaYDameToken();
        Enumerados.categoriaLexica cat=token.getCat();
        if (cat.equals(Enumerados.categoriaLexica.CLIDENT)){
            String nombreFun=token.getLex();
            token=avanzaYDameToken();

             if (token.getCat().equals(Enumerados.categoriaLexica.CLPARAB)){
                    ArrayList<Param> params=reconoceParams(tabla);
                    token=avanzaYDameToken();
                    if(token.getCat().equals(Enumerados.categoriaLexica.CLRETURNS)){
                        token=avanzaYDameToken();
                        if(token.getCat().equals(Enumerados.categoriaLexica.CLTREAL)||token.getCat().equals(Enumerados.categoriaLexica.CLPOINTER)||token.getCat().equals(Enumerados.categoriaLexica.CLTENT)){
                            TipoFun fun=new TipoFun(nombreFun,params,token.getCat(),dir);
                            //creamos una nueva entrada de tabla con el descriptor de tipo "fun";
                            EntradaTabla e=new EntradaTabla(nombreFun,Clase.fun,dir,fun,nivel);
                            //la añadimos a la tabla de simbolos del ambito actual.
                            tabla.getTdS().setIdentificador(e);
                            //nueva tabla apilada,que tiene como tabla propia una nueva tabla y como tabla padre la tabla del ambito actual
                            TablaApilada t=new TablaApilada(new TablaSimbolos(),tabla);
                            //añadimos a la tabla global de funciones la funcion 
                            tablaGlobal.addElem(t);
                            TablaSimbolos tablaSFun=new TablaSimbolos();
                            TablaSimbolos tab=tabla.getTdS();
                            EntradaTabla ent=tab.dameEntradaTabla(nombreFun);
                            TipoFun f=(TipoFun)ent.getDesc();
                            f.setTablaS(tablaSFun);
                            nivel++;
                            TablaApilada nuevaTabla=new TablaApilada(tablaSFun,tabla);
                            setAmbitoActual(nuevaTabla);
                            avanzaYDameToken();
                            Decs(nuevaTabla,nivel);
                            //reconocemos las declaraciones de la funcion.
                          if(!errorDec){
                               errorAcc=reconoceAcciones();
                          }
                           
                            token=dameToken();
                            if (token.getCat().equals(Enumerados.categoriaLexica.CLEND)){
                                token=avanzaYDameToken();
                                if (token.getLex().equals(f.getNombre())){
                                    token=avanzaYDameToken();
                                    if (token.getCat().equals(Enumerados.categoriaLexica.CLPYC)) token=avanzaYDameToken();
                                    else{
                                        errorDec=true;
                                        errores.add("Error en la linea "+linea+" y columna "+columna+" porque se esperaba un token de tipo punto y coma");
                                    }
                                }else{
                                    errorDec=true;
                                    errores.add("Error en la linea "+linea+" y columna "+columna+" porque se esperaba un token de tipo ident");
                                }
                            }else{
                                errorDec=true;
                                errores.add("Error en la linea "+linea+" y columna "+columna+" porque se esperaba un token de tipo end");
                            }
                             this.setAmbitoActual(ambitoActual.getPadre());
                       }
                   }
                   
             }
        }else{
            errorDec=true;
            errores.add("Error en la linea "+linea+" y columna "+columna+" porque se esperaba un token de tipo parentesis abierto");
        }


    }

   
    private void DecVar(TablaApilada tabla,int nivel){
         Token token = dameToken();
         Enumerados.categoriaLexica cat = token.getCat();
         Enumerados.categoriaLexica tipoid=cat;
         String nombreIdent=token.getLex();
         if (cat.equals(Enumerados.categoriaLexica.CLTENT) || cat.equals(Enumerados.categoriaLexica.CLTREAL) || cat.equals(Enumerados.categoriaLexica.CLIDENT)){
         String idD=tokens.get(tokenActual+1).getLex();
         token=avanzaYDameToken();
         cat = token.getCat();

         if(cat.equals(Enumerados.categoriaLexica.CLIDENT)){
              token=avanzaYDameToken();
              cat = token.getCat();


            if(cat.equals(Enumerados.categoriaLexica.CLPYC)){

                TipoBasico t;
                EntradaTabla e;
                if (tipoid.equals(Enumerados.categoriaLexica.CLTENT)){
                    t=new TipoBasico(tipo.ENT,"ENT");                    
                    e=new EntradaTabla(idD,Clase.var,dir,t,nivel);
                    dir+=t.getTamaño();
                    errorDec = (errorDec || !ambitoActual.getTdS().setIdentificador(e));
                }
                else if (tipoid.equals(Enumerados.categoriaLexica.CLTREAL)){
                    t=new TipoBasico(tipo.REAL,idD);                    
                    e=new EntradaTabla(idD,Clase.var,dir,t,nivel);
                    dir+=t.getTamaño();
                    errorDec = (errorDec || !ambitoActual.getTdS().setIdentificador(e));
                }
                else if (tipoid.equals(Enumerados.categoriaLexica.CLIDENT))
                {
                      EntradaTabla ent=ambitoActual.getTdS().dameEntradaTabla(nombreIdent);
                      Clase tipo=ent.getClase();
                      DescTipo d=ent.getDesc();
                      if (d!=null && tipo.equals(Clase.tipo) ){
                         e=new EntradaTabla(idD,Clase.var,dir,d,nivel);
                         errorDec= (errorDec || !ambitoActual.getTdS().setIdentificador(e));
                         dir+=d.getTamaño();
                      }
                      else{
                          errorDec=true;
                          errores.add("Error en la linea "+linea+" y columna "+columna+" porque el tipo referenciado no existe");
                      }
                }
                if (errorDec) errores.add("Error en la linea "+linea+" y columna "+columna+" porque la variable "+idD+" ya ha sido declarada con anterioridad");

                token = avanzaYDameToken();
                cat = token.getCat();
                linea++;
                columna=1;


            }
            else{
            //METER UN ERROR DICIENDO QUE ESPERABAMOS UN TOKEN DE TIPO PYC
                errores.add("Error en la linea "+linea+" y columna "+columna+" porque hemos encontrado un token de tipo "+token.getLex()+" cuando esperabamos un token de tipo ;");
                error=true;
            }
        }
        else{
        //METER ERROR DICIENDO QUE ESPERABAMOS UN TOKEN DE TIPO IDENT
            errores.add("Error en la linea "+linea+" y columna "+columna+" porque hemos encontrado un token de tipo "+token.getLex()+" cuando esperabamos un token de tipo IDENT");
            errorDec=true;
        }

      }else{ 
             errores.add("Error en la linea "+linea+" y columna "+columna+" porque hemos encontrado un token de tipo "+token.getLex()+"cuando esperabamos un token de tipo real o entero o identificador");
             errorDec=true;
             
           }


    }


    public TipoArray reconoceArray(Enumerados.categoriaLexica catLexicaTipoBase,String nombreTipoBase ){
        Token token =avanzaYDameToken();
        Enumerados.categoriaLexica cat=token.getCat();
        if (cat.equals(Enumerados.categoriaLexica.CLCORCHAB)){
            token=avanzaYDameToken();
            cat=token.getCat();
            if (cat.equals(Enumerados.categoriaLexica.CLENT)){
                int numelems=(Integer.valueOf(token.getLex()));
                token=avanzaYDameToken();
                cat=token.getCat();
                if (cat.equals(Enumerados.categoriaLexica.CLCORCHCER)){
                    token=avanzaYDameToken();
                    cat=token.getCat();
                    if (cat.equals(Enumerados.categoriaLexica.CLIDENT)){
                        String id=token.getLex();
                        token=avanzaYDameToken();
                        cat=token.getCat();
                        if(cat.equals(Enumerados.categoriaLexica.CLPYC)){
                            TipoArray array;
                            EntradaTabla e;
                            if (catLexicaTipoBase.equals(Enumerados.categoriaLexica.CLTENT)){
                                array=new TipoArray(numelems,new TipoBasico(tipo.ENT,"ENT"),id);
                                return array;
                            }
                            else if (catLexicaTipoBase.equals(Enumerados.categoriaLexica.CLTREAL)){
                                array=new TipoArray(numelems,new TipoBasico(tipo.REAL,"REAL"),id);
                                return  array;
                            }
                            else if (catLexicaTipoBase.equals(Enumerados.categoriaLexica.CLIDENT)){
                                     if (ambitoActual.getTdS().estaID(nombreTipoBase)){
                                      EntradaTabla entrada=ambitoActual.getTdS().dameEntradaTabla(nombreTipoBase);
                                      array=new TipoArray(numelems,entrada.getDesc(),id);
                                      return  array;
                                     }
                                     else{
                                         columna-=5;
                                         errores.add("Error en la linea "+linea+" y columna "+columna+", el tipo basico del array no existe");
                                         errorDec=true;
                                     }


                            }else{
                                errores.add("Error en la linea "+linea+" y columna "+columna+", porque esperabamos un token de tipo ENT o REAL o IDENT");
                            }
                            linea++;
                            avanzaYDameToken();
                        }
                        else{
                            errorDec=true;
                            errores.add("Error en la linea "+linea+" y columna "+columna+" porque hemos encontrado un token de tipo "+token.getLex()+" cuando esperabamos un token de tipo CPYC");
                        }
                    }else{
                        errores.add("Error en la linea "+linea+" y columna "+columna+", porque hemos encontrado un token de tipo "+token.getLex()+" cuando esperabamos un token de tipo IDENT");
                        errorDec=true;
                    }
                }else{
                    errores.add("Error en la linea "+linea+" y columna "+columna+", porque hemos encontrado un token de tipo "+token.getLex()+" cuando esperabamos un token de tipo CLCORCHCER");
                    errorDec=true;
                }
            }else{
                errores.add("Error en la linea "+linea+" y columna "+columna+", porque hemos encontrado un token de tipo "+token.getLex()+" cuando esperabamos un token de tipo CLENT");
                errorDec=true;
            }

       }else{
            errores.add("Error en la linea "+linea+" y columna "+columna+", porque hemos encontrado un token de tipo "+token.getLex()+" cuando esperabamos un token de tipo CLCORCHAB");
            errorDec=true;
        }
        return null;

    }

    public EntradaTabla reconoceRegistro(){
        int despCampo=0;
        Token token = avanzaYDameToken();
        Enumerados.categoriaLexica cat= token.getCat();
        TipoRegistro campos = new TipoRegistro(token.getLex());
        while (!cat.equals(Enumerados.categoriaLexica.CLENDREC)&& !cat.equals(Enumerados.categoriaLexica.CLTIPO) && tokenActual<=tokens.size()){
            CampoReg campo= reconoceCampoRegistro(despCampo);
            if (campo!=null){
                despCampo=despCampo+campo.getTipo().getTamaño();
                campos.addCampo(campo);
                token = avanzaYDameToken();
                cat=token.getCat();
            }
            else return null;


        }
        if (token.getCat().equals(Enumerados.categoriaLexica.CLENDREC)){
        token = avanzaYDameToken();
        cat= token.getCat();
        if(cat.equals(Enumerados.categoriaLexica.CLIDENT)){
            String id=token.getLex();
            campos.setNombre(id);
            token = avanzaYDameToken();
            cat= token.getCat();
            if (cat.equals(Enumerados.categoriaLexica.CLPYC)){               
                EntradaTabla e= new EntradaTabla(id,Clase.tipo,dir,campos,0);                
                return e;
            }else{
                errorDec=true;
                errores.add("Error en la linea "+linea+" y columna "+columna+" porque hemos encontrado un token de tipo "+token.getLex()+" cuando esperabamos un token Punto y Coma");
            }
        }
        else{
            errorDec=true;
            errores.add("Error en la linea "+linea+" y columna "+columna+" porque hemos encontrado un token de tipo "+token.getLex()+" cuando esperabamos un token de tipo CLIDENT");
        }
        }
        else{
            errorDec=true;
            errores.add("Error en la linea "+linea+" y columna "+columna+" porque hemos encontrado un token de tipo "+token.getLex()+" cuando esperabamos un token de tipo CLENDREC");
        }
        return null;
    }

        public CampoReg reconoceCampoRegistro(int despCampo){

            Token token = dameToken();
            Enumerados.categoriaLexica cat= token.getCat();
            Token token2= (Token) tokens.get(tokenActual+1);
            Enumerados.categoriaLexica cat2= token2.getCat();
           if(cat2.equals(Enumerados.categoriaLexica.CLCORCHAB)){
                  TipoArray array=reconoceArray(token.getCat(),token.getLex());
                  CampoReg c=null;
                  if (array!=null){
                  despCampo+=array.getTamaño();
                  EntradaTabla e=new EntradaTabla(array.getNombre(),Clase.tipo,dir,array,0);
                  c=new CampoReg(e.getId(),e.getDesc(),0);
                  }
                  return c;
            }
            else if(cat.equals(Enumerados.categoriaLexica.CLTENT) || cat.equals(Enumerados.categoriaLexica.CLTREAL) || cat.equals(Enumerados.categoriaLexica.CLIDENT))
            {
               String nombreId=token.getLex();
               token = avanzaYDameToken();
               String tipoid=cat.toString();
               cat = token.getCat();
               if(cat.equals(Enumerados.categoriaLexica.CLIDENT)){
                    String id=token.getLex();
                    token = avanzaYDameToken();
                    cat = token.getCat();
                    TipoBasico t;
                               if(cat.equals(Enumerados.categoriaLexica.CLPYC)){

                                if (tipoid.equals("CLTENT")){
                                     t=new TipoBasico(tipo.ENT,id);
                                     CampoReg campo= new CampoReg(id,t,despCampo);
                                     despCampo=despCampo+t.getTamaño();
                                     return campo;
                               }
                               else if (tipoid.equals("CLTREAL")){
                                    t=new TipoBasico(tipo.REAL,id);
                                    CampoReg campo= new CampoReg(id,t,0);
                                    despCampo=despCampo+t.getTamaño();
                                    return campo;
                               }
                               else if (tipoid.equals("CLIDENT")){
                                   DescTipo d=ambitoActual.getTdS().dameEntradaTabla(nombreId).getDesc();
                                   if (d!=null && !d.getTipo().equals(tipo.PUNT)){
                                       CampoReg campo= new CampoReg(id,d,despCampo);
                                       return campo;
                                   }
                                   else if (d!=null && d.getTipo().equals(tipo.PUNT)){
                                       TipoPuntero p=(TipoPuntero)d;
                                       CampoReg campo= new CampoReg(id,p,despCampo);
                                       return campo;
                                   }
                               }
                      }else{
                                   errorDec=true;
                                   errores.add("Error en la linea "+linea+" y columna "+columna+" ,se esperaba un token de tipo Punto y coma");
                               }

               }else{
                   errorDec=true;
                   errores.add("Error en la linea "+linea+" y columna "+columna+" ,se esperaba un token de tipo Identificador");
               }

           }else{
                errorDec=true;
                errores.add("Error en la linea "+linea+" y columna "+columna+" ,se esperaba un token de tipo Identificador o de tipo REAL o ENTERO o [");
            }
          return null;
        }

         public ArrayList<Param> reconoceParams(TablaApilada tabla){
            ArrayList<Param> params=new ArrayList<Param>();
            Token token=avanzaYDameToken();
            while (!token.getCat().equals(Enumerados.categoriaLexica.CLPARCER)){
                Param param=reconoceParam(tabla,nivel);
                params.add(param);
                token=avanzaYDameToken();
            }
            return params;
       }

        public Param reconoceParam(TablaApilada tabla,int nivel){
            Token token=dameToken();
            if (token.getCat().equals(Enumerados.categoriaLexica.CLTENT)|| token.getCat().equals(Enumerados.categoriaLexica.CLTREAL)|| token.getCat().equals(Enumerados.categoriaLexica.CLIDENT)){
                Enumerados.categoriaLexica tipoPar=token.getCat();
                if (token.getCat().equals(Enumerados.categoriaLexica.CLIDENT)){
                    DescTipo d=tabla.getTdS().dameEntradaTabla(token.getLex()).getDesc();
                }
                token=avanzaYDameToken();
                Modo m;
                if (token.getCat().equals(Enumerados.categoriaLexica.CLAMP)){
                    m=Modo.var;
                    token=avanzaYDameToken();
                 }
                 else m=Modo.valor;
                 if(token.getCat().equals(Enumerados.categoriaLexica.CLIDENT)){
                         String nombreParam=token.getLex();
                         token=avanzaYDameToken();
                          TipoBasico t;
                          Param p;
                          if (token.getCat().equals(Enumerados.categoriaLexica.CLCOMA) || token.getCat().equals(Enumerados.categoriaLexica.CLPARCER)){
                             if(tipoPar.equals((Enumerados.categoriaLexica.CLTENT))){
                                 t=new TipoBasico(tipo.ENT,"ENT");
                                 p=new Param(m,t,nombreParam);
                                 if (token.getCat().equals(Enumerados.categoriaLexica.CLPARCER)) this.tokenActual--;
                                 return p;
                                 }
                             else if(tipoPar.equals((Enumerados.categoriaLexica.CLTREAL))){
                                 t=new TipoBasico(tipo.REAL,"REAL");
                                 p=new Param(m,t,nombreParam);
                                 if (token.getCat().equals(Enumerados.categoriaLexica.CLPARCER)) this.tokenActual--;
                                 return p;
                             }
                         }
                 }
                 else{
                     errorDec=true;
                     errores.add("Error en la linea "+linea+" y columna "+columna+" ,se esperaba un token de tipo coma o parentesis cerrado");
                     }
                    
            }else{
                errorDec=true;
                errores.add("Error en la linea "+linea+" y columna "+columna+" ,se esperaba un token de tipo Identificador o ampersand");
            }
            return null;
        }
        
/*******************************************************************************
 *                                                                             *
 *  ACCIONES                                                                   *
 *                                                                             *
 *      Accs  ::= Acc RAccs                                                    *
 *      RAccs ::= Acc RAccs | λ                                                *
 *                                                                             *
 ******************************************************************************/

    private boolean reconoceAcciones(){
        boolean errAcc;
        boolean errRA=false;
        StringBuffer tipoAcc=new StringBuffer("");
  
        Token actual=dameTokenActual();
        if(actual.getCat().equals(Enumerados.categoriaLexica.CLEOF)){
            errores.add("No se ha encontrado ninguna accion y la seccion de acciones no puede ser vacia.");
            return true;
        }

/*      Reconocemos la primera accion.                                        */
        errAcc=reconoceAcc(tipoAcc);

/*      Pedimos el siguiente token para comprobar si es final de fichero.     */
        actual=dameTokenActual();

/*      Seguimos procesando las acciones en el caso de que no se haya producido
        ningun error en la primera accion y no hemos reconocido ningun token del
        tipo de EOF, ENDWHILE, ELSE o ENDIF.
        Es decir, tenemos otra accion que reconocer.                          */
        if(!errAcc){
            if((!actual.getCat().equals(Enumerados.categoriaLexica.CLEOF))
                    &&(!actual.getCat().equals(Enumerados.categoriaLexica.CLENDWHILE))
                    &&(!actual.getCat().equals(Enumerados.categoriaLexica.CLELSE))
                    &&(!actual.getCat().equals(Enumerados.categoriaLexica.CLENDIF))
                    &&(!actual.getCat().equals(Enumerados.categoriaLexica.CLELSIF))
                    &&(!actual.getCat().equals(Enumerados.categoriaLexica.CLEND))){
/*              Reconocemos o procesamos el resto de acciones.                */
                errRA=reconoceRAccs();
            }
        }
/*      Hemos terminado de reconocer todas las acciones. Devolvemos la
        posibilidad de que se haya podido producir algun error en el resto de
        acciones, en la primera accion o que se haya producido un error de
        tipos.                                                                */
        return (errAcc || errRA || tipoAcc.toString().equals(Enumerados.tipoIdentificador.TERR.toString()));
    }
/*  Metodo semejante al anterior. Obviamos los comentarios.                   */
    private boolean reconoceRAccs(){
        boolean errAcc;
        boolean errRA=false;
        StringBuffer tipoAcc=new StringBuffer("");

        errAcc = reconoceAcc(tipoAcc);

        Token actual=dameTokenActual();

        if(!errAcc){
/*      Seguimos procesando las acciones en el caso de que no se haya producido
        ningun error en la primera accion y no hemos reconocido ningun token del
        tipo de EOF, ENDWHILE, ELSE o ENDIF.
        Es decir, tenemos otra accion que reconocer.                          */
            if((!actual.getCat().equals(Enumerados.categoriaLexica.CLEOF))
                    &&(!actual.getCat().equals(Enumerados.categoriaLexica.CLENDWHILE))
                    &&(!actual.getCat().equals(Enumerados.categoriaLexica.CLELSE))
                    &&(!actual.getCat().equals(Enumerados.categoriaLexica.CLENDIF))
                    &&(!actual.getCat().equals(Enumerados.categoriaLexica.CLELSIF))
                    &&(!actual.getCat().equals(Enumerados.categoriaLexica.CLEND))){

                    errRA = reconoceRAccs();
            }
        }
        return (errAcc || errRA || tipoAcc.toString().equals(Enumerados.tipoIdentificador.TERR.toString()));
    }

/*******************************************************************************
 *                                                                             *
 *  ACCION                                                                     *
 *                                                                             *
 *      Acc ::= Exp ;                                                          *
 *                                                                             *
 *  Hay que contar con que Exp puede ir entre parentesis. Estos se procesan en *
 *  EXPRESION ya que es aqui donde existira la recursiond Fact y donde se      *
 *  trataran los parentesis de forma general.                                  *
 *                                                                             *
 ******************************************************************************/

    private boolean reconoceAcc(StringBuffer tipohRA){
        StringBuffer tipoExp=new StringBuffer("");
        boolean errExp=false;
        /* Si el token es de tipo end, significa que estamos reconociendo la
         ultima accion de la declaracion de acciones de una funcion. */
        Token actual=dameTokenActual();
        if(actual.getCat().equals(Enumerados.categoriaLexica.CLEND)){
            tipohRA.append("TEND");
            return errExp;
        }
/*      Reconocemos o procesamos la expresion                                 */
        errExp=reconoceExp(tipoExp);
/*      Si no se ha producido ningun error comprobamos el siguiente token. Este
        tiene que ser un ; sino devolvemos un error.                          */
        if(!errExp){
            actual=dameTokenActual();
/*          Comprobamos que no nos llegue del analizador lexico un token
            erroneo. Si es asi, tendremos que encontrar el final de esta accion
            para procesar la siguiente o el final de fichero para terminar    */
            if(actual.getCat().equals(Enumerados.categoriaLexica.CLERROR)){
/*              Buscamos el ; o el final de fichero para pasar a procesar la
                siguiente accion. Indicamos el error correspondiente          */
                errores.add("Token en la linea "+linea+" y columna "+columna+" erroneo. Token desconocido");
                while(!actual.getCat().equals(Enumerados.categoriaLexica.CLPYC)
                        || !actual.getCat().equals(Enumerados.categoriaLexica.CLEOF)){
                    siguienteToken();
                    actual=dameTokenActual();
                }
            }
/*          El siguiente token que debemos reconocer debe ser un ;            */
            if (!actual.getCat().equals(Enumerados.categoriaLexica.CLPYC)){

                errores.add("No encontrado el token ; al final de la linea "+linea);
                return true;
            }
/*          Si se ha reconocido el ; se termina de procesar la accion y se
            avanza el token para dejar preparada la siguiente accion y se
            devuelven los correspondientes errores ademas de actualizar las
            variables de linea y columna para el control de errores.          */
            siguienteToken();
            tipohRA.append(tipoExp);
            linea++;
            columna=1;
            ambigua=new ArrayList();
        }
        return errExp;

    }
/*******************************************************************************
 *                                                                             *
 *  EXPRESION                                                                  *
 *                                                                             *
 *      Exp ::= IEXP | IIf | IWhile | IDesig | IReturn                         *
 *                                                                             *
 *  Recordemos que las expresiones pueden ir precedidas por parentesis y que de*
 *  ser asi tenemos que tenerlos en cuenta a la hora de procesar la expresion. *
 *                                                                             *
 ******************************************************************************/

    private boolean reconoceExp(StringBuffer tipoExp){
        boolean errIExp=false;
        boolean errIf=false;
        boolean errWhile=false;
        boolean errDesig=false;

        Token actual=dameTokenActual();

        if (actual.getCat().equals(Enumerados.categoriaLexica.CLIF)){
            StringBuffer tipoIf = new StringBuffer("");
            errIf=reconoceIf(tipoIf);
            tipoExp.append(tipoIf);
        }
        else if (actual.getCat().equals(Enumerados.categoriaLexica.CLWHILE)){
            StringBuffer tipoWhile = new StringBuffer("");
            errWhile=reconoceWhile(tipoWhile);
            tipoExp.append(tipoWhile);
        }
        else if (actual.getCat().equals(Enumerados.categoriaLexica.CLALLOC)
                ||actual.getCat().equals(Enumerados.categoriaLexica.CLFREE) ){
            StringBuffer tipoDesig = new StringBuffer("");
            errDesig=reconoceDesig(tipoDesig);
            tipoExp.append(tipoDesig);
        }
        else{
            StringBuffer tipoIExp = new StringBuffer("");
            errIExp=reconoceIExp(tipoIExp);
            tipoExp.append(tipoIExp);
        }
        return (errIf||errWhile||errIExp||errDesig);
}
/*******************************      IF       ********************************/

    private boolean reconoceIf(StringBuffer tipoIf){
        boolean errPIf=false;
        StringBuffer tipoPIf=new StringBuffer("");

        /* Avanzamos el token para pasar a reconocer la parte if. */
        siguienteToken();
        /* Reconocemos la parte if de la instruccion. */
        errPIf=reconocePIf(tipoPIf);
        /* Comprobamos que el token final de la expresion sea ENDIF. */
        Token actual=dameTokenActual();
        if(!actual.getCat().equals(Enumerados.categoriaLexica.CLENDIF)){
            errores.add("La estructura de la instruccion IF en la linea "+linea+" no es correcta."
                        + "Se esperaba un token ENDIF en la columna "+columna);
            return true;
        }
        siguienteToken();
        /* Devolvemos el tipo de la expresion resultante. */
        tipoIf.append(tipoPIf);
        return errPIf;
    }
    private boolean reconocePIf(StringBuffer tipoPIf){
        boolean errEB,errRA,errPE=false;
        StringBuffer tipoEB=new StringBuffer("");
        int etqAccs1,etqAccs2=-1;

        /* Reconocemos la expresion basica. */
        errEB=reconoceExpBasica(tipoEB);
        /* Sino se ha producido error, seguimos analizando la expresion. */
        if(!errEB){
            Token actual=dameTokenActual();
            /* Comprobamos que el siguiente token sea THEN. */
            if(!actual.getCat().equals(Enumerados.categoriaLexica.CLTHEN)){
                errores.add("La estructura de la instruccion IF en la linea "+linea+" no es correcta."
                        + "Se esperaba un token THEN en la columna "+columna);
                return true;
            }
            else{
                /* Avanzamos el token para pasar a reconocer el cuerpo de la
                 expresion. */
                siguienteToken();
                /* Cogemos la etiqueta de salto condicional para parchear
                 posteriormente. */
                etqAccs1=etiqueta;
                /* Añadimos la instruccion de salto condicional. */
                codigo.add("ir_f ?\n");
                etiqueta++;
                /* Reconocemos el cuerpo del if.*/
                errRA=reconoceAcciones();
                if(!errRA){
                    /* Guardamos la etiqueta del salto incondicional para
                     parcherala despues de analizar la parte del else. */
                    etqAccs2=etiqueta;
                    /* Añadimos la instruccion de salto incondicional para
                     saltar si hemos ejecutado las instrucciones posteriores al
                     if. */
                    codigo.add("ir_a ?\n");
                    etiqueta++;
                    /* Parcheamos la instruccion de salto condicional anterior
                     para que ejecute a partir de aqui el codigo correspondiente
                     a la rama del else. */
                    parchea(etqAccs1,etiqueta);
                    /* Reconocemos la parte ELSE de la instruccion. */
                    actual=dameTokenActual();
                    errPE=reconocePElse();
                    /* Parcheamos el salto incondicional para que se salte la
                     parte del else si hemos entrado por la rama del if. */
                    parchea(etqAccs2,etiqueta);
                    /* Calculamos el tipo a devolver. */
                    if(tipoEB.toString().equals(tipoIdentificador.LOG.toString()))
                            tipoPIf.append("TIF");
                    else tipoPIf.append("TERR");
                    return errPE;
                }
            }
        }
        return true;
    }

    private boolean reconocePElse(){
        boolean errRA,errPEI=false;

        /* Pedimos el token actual para */
        Token actual=dameTokenActual();
        if(actual.getCat().equals(Enumerados.categoriaLexica.CLELSE)){
            /* Avanzamos el token para pasar a reconocer el cuerpo de la
             expresion. */
            siguienteToken();
            /* Reconocemos el cuerpo del else.*/
            errRA=reconoceAcciones();
            return errRA;
        }
        if(actual.getCat().equals(Enumerados.categoriaLexica.CLELSIF)){
            errPEI=reconocePElseIf();
            return errPEI;
        }
        return false;
    }

    private boolean reconocePElseIf(){
        boolean errPIf=false;
        StringBuffer tipoPIf=new StringBuffer("");

        /* Avanzamos el token para pasar a reconocer el cuerpo de la
         expresion. */
        siguienteToken();
        /* Reconocemos el nuevo if.*/
        errPIf=reconocePIf(tipoPIf);
        return errPIf;

    }

/******************************      WHILE       ******************************/

    private boolean reconoceWhile(StringBuffer tipoWhile){
        boolean errEB,errRA=false;
        StringBuffer tipoEB=new StringBuffer("");
        int etqEB,etqAcc=-1;

        /* Avanzamos el token para pasar a reconocer la expresion basica. */
        siguienteToken();
        /* Guardamos la etiqueta donde se situará la primera instrucción de la
         expresion basica de condicion del while. */
        etqEB=etiqueta;
        /* Reconocemos la expresion basica. */
        errEB=reconoceExpBasica(tipoEB);
        /* Sino se ha producido error, seguimos analizando la expresion. */
        if(!errEB){
            Token actual=dameTokenActual();
            /* Comprobamos que el siguiente token sea DO. */
            if(!actual.getCat().equals(Enumerados.categoriaLexica.CLDO)){
                errores.add("La estructura de la instruccion While en la linea "+linea+" no es correcta."
                        + "Se esperaba un token DO en la columna "+columna);
                return true;
            }
            else{
                /* Avanzamos el token para pasar a reconocer el cuerpo de la
                 expresion. */
                siguienteToken();
                /* Introducimos la insutruccion de salto condicional. */
                etqAcc=etiqueta;
                codigo.add("ir_f ?\n");
                etiqueta++;
                /* Reconocemos el cuerpo del while.*/
                errRA=reconoceAcciones();
                if(!errRA){
                    /* Comprobamos que reconocemos un token ENDWHILE despues del
                     cuerpo de la intruccion*/
                    actual=dameTokenActual();
                    if(!actual.getCat().equals(Enumerados.categoriaLexica.CLENDWHILE)){
                        errores.add("La estructura de la instruccion While en la linea "+linea+" no es correcta."
                            + "Se esperaba un token ENDWHILE en la columna "+columna);
                        return true;
                    }
                    /* Introducimos la instruccion de salto incondicional. */
                    codigo.add("ir_a "+etqEB+"\n");
                    etiqueta++;
                    /* Parcheamos el salto de la condicion. */
                    parchea(etqAcc,etiqueta);
                    /* Calculamos el tipo a devolver. */
                    if(tipoEB.toString().equals(tipoIdentificador.LOG.toString()))
                            tipoWhile.append("TWHILE");
                    else tipoWhile.append("TERR");
                    /* Avanzamos el token para que se reconozca el ; y acabe con
                     exito el analisis de la accion. */
                    siguienteToken();
                    /* Devolvemos que no se ha producido ningun error. */
                    return false;
                }
            }
        }
        /* Si se ha producido un error en la expresion basica o en las acciones
         del cuerpo de la instruccion, devolvemos true para indicar que ha
         habido un error en la expresion.*/
        return true;
    }

/******************************      DESIG       ******************************/
    private boolean reconoceDesig(StringBuffer tipoDesig){
        boolean errDesig=false;
        boolean errMem=false;
        StringBuffer tipoMem=new StringBuffer("");

        Token accion=dameTokenActual();
        siguienteToken();
        errMem=reconoceMem(tipoMem);
        if(!errMem && ambitoActual.getTdS().dameEntradaTabla(tipoMem.toString()).getDesc().getTipo().equals(tipo.PUNT)){
                TipoPuntero puntero = (TipoPuntero) ambitoActual.getTdS().dameEntradaTabla(tipoMem.toString()).getDesc();
                int tam=puntero.getTipoApuntado().getTamaño();
                if(accion.getCat().equals(Enumerados.categoriaLexica.CLALLOC)){
                    codigo.add("alloc "+tam+"\n");
                    codigo.add("desapila_ind\n");
                    etiqueta=etiqueta+2;
                }
                else{
                    codigo.add("free "+tam+"\n");
                    etiqueta++;
                }
                tipoDesig.append("TDESIG");
            }
            else{
                errores.add("El designador utilizado en la linea "+linea+" para reservar memoria no es de tipo puntero.");
                tipoDesig.append("TERR");
                return true;
            }
////        else{
////            errores.add("El token recibido en la linea "+linea+" no es un designador.");
////            tipoDesig.append("TERR");
////            return true;
////        }
        //siguienteToken();
        return errDesig;
    }
    
/*******************************************************************************
 *                                                                             *
 *  IEXPRESION                                                                 *
 *                                                                             *
 *      IExp ::= IN Mem | OUT IAsig | IAsig                                    *
 *                                                                             *
 *                                                                             *
 ******************************************************************************/
    private boolean reconoceIExp(StringBuffer tipoIExp){
        boolean errIAsig=false;

        Token actual=dameTokenActual();
        
/*******************************      IN       ********************************/
            
        if (actual.getCat().equals(Enumerados.categoriaLexica.CLIN)){
            boolean errMem = false;
            StringBuffer tipoMem=new StringBuffer("");

            siguienteToken();
            actual=dameTokenActual();
            errMem=reconoceMem(tipoMem);
            if(!errMem){
                if(tipoMem.toString().equals("ENT") || tipoMem.toString().equals("REAL")){
                    codigo.add("in " + ambitoActual.getTdS().getTipo(actual.getLex())+ "\n" );
                    etiqueta++;
                    codigo.add("desapila_ind\n");
                    etiqueta++;
                    tipoIExp.append(tipoMem.toString());
                }
                else{
                    errores.add("La variable usada para la instruccion in en la linea "+linea+" y columna "+columna+
                            " no es de tipo entero o real");
                    tipoIExp.append("TERR");
                }
            }
            return errMem;
////            siguienteToken();
////            actual=dameTokenActual();
/////*          Si es de tipo IN, comprobamos que el siguiente token sea de
////            tipo IDENT. Sino, devolvemos un error de tipo.                */
////            if (!actual.getCat().equals(Enumerados.categoriaLexica.CLIDENT)){
////                tipoIExp.append("TERR");
////                errores.add("Token incorrecto en la linea "+linea+" y columna "+columna+". Se esperaba un token de tipo IDENTIFICADOR.");
////                return true;
////            }
////            else{
////             /* Comprobamos que el identificador que acabamos de leer haya
////                sido declarado previamente en la seccion de declaraciones.
////                Para ello, cogemos el lexema del identificador (es decir,
////                del token actual) y lo buscamos en la tabla de simbolos que
////                heredamos de Exp. */
////                if(ambitoActual.getTdS().estaID(actual.getLex())){
////                     /* Generamos el codigo apropiado para la que la maquina
////                        p ejecute el programa correctamente. Devolvemos tb
////                        el tipo de expresion que acabamos de procesar para
////                        controlar posibles errores de tipo. */
////                        codigo.add("in " + ambitoActual.getTdS().getTipo(actual.getLex())+ "\n" );
////                        etiqueta++;
////                        codigo.add("desapila_dir " + ambitoActual.getTdS().getDir(actual.getLex())+ "\n");
////                        etiqueta++;
////                        tipoIExp.append((ambitoActual.getTdS().getTipo(actual.getLex())).toString());
////                }
////                else{
////                 /* Si no esta el identificador registramos el error tanto
////                    en el array de errores como en el tipo de la expresion.
////                    No devolvemos true ya que este es un error contextual
////                    que no para la ejecucion del analizador sintatico. */
////                    errores.add("Error sintactico contextual en la linea "+linea +" y columna "+columna+". La variable "+actual.getLex()+ " no ha sido declarado previamente");
////                    tipoIExp.append("TERR");
////                    siguienteToken();
////                    return false;
////                }
////            }
////            siguienteToken();
        }
/*******************************      IN       ********************************/

/*******************************      OUT      ********************************/

        else if (actual.getCat().equals(Enumerados.categoriaLexica.CLOUT)){
               StringBuffer tipoIAsig=new StringBuffer("");

               /* Si hemos reconocido el token OUT, avanzamos el token
               actual y pasamos a reconocer la ExpBasica.*/
               siguienteToken();
             
               errIAsig=reconoceIAsig(tipoIAsig);
               if(!(tipoIAsig.toString().equals("ENT") || tipoIAsig.toString().equals("REAL"))){
                   errores.add("El tipo de la expresion en la linea "+linea+" para la instruccion out no es de tipo entero o real");
                   errIAsig=true;
               }
               tipoIExp.append(tipoIAsig);
               codigo.add("out\n");
               etiqueta++;
        }
/*******************************      OUT      ********************************/

/******************************      IAsig      *******************************/

        /*Segun la gramatica pasariamos a reconoceIAsig de todas todas, pero en
         la implementacion tenemos que distinguir cuando pasamos a reconoceIAsig
         porque tenemos una instruccion de asignacion verdaderamente, es decir,
         nos llega un IDENT y cuando pasamos a reconoceIAsig porque no hemos
         encontrado ninguna instruccion que "sepamos" ejecutar. En este ultimo
         caso simplemente terminamos el metodo reconoceIExp y no reconocemos esa
         linea porque no es una expresion valida. De esta forma, pueden compilar
         programas como 2; sin que de error. Pero no hace nada, claro esta.*/
        else{
            StringBuffer tipoIAsig = new StringBuffer("");
            errIAsig=reconoceIAsig(tipoIAsig);
            tipoIExp.append(tipoIAsig);
        }
        return errIAsig;
 }

/*******************************************************************************
 *                                                                             *
 *  IAsig                                                                      *
 *                                                                             *
 *      IAsig ::= IDENT=IAsig | ExpBasica                                      *
 *                                                                             *
 *                                                                             *
 ******************************************************************************/

    private boolean reconoceIAsig(StringBuffer tipoIAsig){
        boolean duplicar=false;
        boolean errIAsig=false;
        boolean errExpBasica=false;
        boolean errMem=false;

        Token actual=dameTokenActual();
        /* Comprobamos si estamos en una expresion de asignacion o en una
         expresion basica. */
        int temporal=tokenActual;
        while(!(tokens.get(temporal).getCat().equals(Enumerados.categoriaLexica.CLASIG)
            ||tokens.get(temporal).getCat().equals(Enumerados.categoriaLexica.CLPYC)
            ||tokens.get(temporal).getCat().equals(Enumerados.categoriaLexica.CLEOF))){
                temporal++;
        }
        if(tokens.get(temporal).getCat().equals(Enumerados.categoriaLexica.CLASIG)){
            actual=dameTokenActual();
            if (actual.getCat().equals(Enumerados.categoriaLexica.CLIDENT)){
                /* Comprobamos si esta variable es el factor o
                 expresion a asignar de una expresion anterior.
                 De ser asi, debemos duplicar el ultimo valor de la pila ya que
                 se trata de la direccion de la variable y hay que volver a
                 apilar en la pila el valor asociado a dicha variable. Es decir,
                 necesitamos dos veces la direccion de la variable, una para
                 guardar en ella el valor de la expresion asignada y otra vez
                 cargar su valor ya que es la expresion de otra variable. */
                Token anteriorActual=(Token) tokens.get(tokenActual-1);
                if ((anteriorActual.getCat().equals(Enumerados.categoriaLexica.CLASIG))
                    || (anteriorActual.getCat().equals(Enumerados.categoriaLexica.CLOUT)))
                    duplicar=true;
                /* Reconocemos la variable. */
                StringBuffer tipoMem=new StringBuffer("");
                errMem=reconoceMem(tipoMem);
                if(!errMem){
                    /* Comprobamos que no se produzca recursion en las asignaciones. */
                    if(!ambigua.contains(actual.getLex())){
                        ambigua.add(actual.getLex());
                        actual=dameTokenActual();
                        /* Comprobamos que el siguiente token leido sea el = . Sino,
                         procesamos el correspondiente error. */
                        if (!actual.getCat().equals(Enumerados.categoriaLexica.CLASIG)){
                            errores.add("Error sintactico incontextual en la linea "+linea +" y columna "+columna+". Se esperaba un token de tipo asignacion (=)");
                            tipoIAsig.append("TERR");
                            return true;
                        }
                        else{
                            /* Pedimos el siguiente token a procesar. */
                            siguienteToken();
                            actual=dameTokenActual();
                            /* Pasamos a reconocer ExpBasica. Recogemos el tipo de la
                            expresion y el codigo que se genera para la maquina p en los
                            argumentos que le pasamos. La funcion nos devuelve si ha
                            encontrado algun error en el procesamiento. */

                            StringBuffer tipoIAsig1=new StringBuffer("");
                            errIAsig=reconoceIAsig(tipoIAsig1);
                            if(!errIAsig){
                                /* Comprobamos el tipo final que tiene que tener la expresion
                                 de asignacion */
                                if ((tipoMem.toString().equals("REAL"))
                                &&((tipoIAsig1.toString().equals("REAL"))
                                        ||(tipoIAsig1.toString().equals("ENT")))){

                                    if (tipoIAsig1.toString().equals("ENT")){
                                        codigo.add("CASTING_R"+"\n");
                                        etiqueta++;
                                    }

                                    tipoIAsig.append("REAL");
                                }
                                else if (tipoMem.toString().equals(tipoIAsig1.toString())){
                                    tipoIAsig.append(tipoMem.toString());
                                }
                                else if (tipoIAsig1.toString().equals("TNULL")
                                        && ambitoActual.getTdS().dameEntradaTabla(tipoMem.toString()).getDesc().getTipo().equals(tipo.PUNT)){
                                    tipoIAsig.append(tipoMem);
                                }
                                else{
                                    errores.add("Error sintactico contextual en la linea "+linea +" y columna "+columna--+". El tipo del simbolo y el tipo de la expresion que se le asignará son incompatibles.");
                                    tipoIAsig.append("TERR");
                                    return true;
                                }
                                if(tipoIAsig1.toString().equals("REAL") || tipoIAsig1.toString().equals("ENT") || tipoIAsig1.toString().equals("TNULL")){
                                    codigo.add("desapila_ind\n");
                                    etiqueta++;;
                                    if(duplicar){
                                        codigo.add("duplicar\n");
                                        etiqueta++;
                                    }
                                }
                                else{
                                    codigo.add("mueve "+ambitoActual.getTdS().dameEntradaTabla(tipoMem.toString()).getDesc().getTamaño()+"\n");
                                    etiqueta++;
                                }
                            }
                        }
                    }
                    else{
                        errores.add("El identificador usado en la linea "+linea+" y columna "+columna+" ya ha sido referenciado en dicha intruccion de asignacion. ");
                        return true;
                    }
                }
                else return true;
            }
            else{
                errores.add("El token de la linea "+linea+" y columna "+columna+" no es de tipo Mem, necesario para la asignacion.");
                return true;
            }
        }
        else if(columna==1){
            while(actual.getCat().equals(Enumerados.categoriaLexica.CLPYC)){
                siguienteToken();
            }
            return false;
        }
        else{
            StringBuffer tipoExpBasica=new StringBuffer("");
            /* Pasamos a reconocer ExpBasica. Recogemos el tipo de la
            expresion y el codigo que se genera para la maquina p en los
            argumentos que le pasamos. La funcion nos devuelve si ha
            encontrado algun error en el procesamiento. */
            errExpBasica=reconoceExpBasica(tipoExpBasica);

            errIAsig=errExpBasica;
   
            tipoIAsig.append(tipoExpBasica);
        }
        return errIAsig;
}

//        Token actual=dameTokenActual();
//        Token siguienteActual=(Token) tokens.get(tokenActual+1);
//
//        if ((actual.getCat().equals(Enumerados.categoriaLexica.CLIDENT))
//            && (siguienteActual.getCat().equals(Enumerados.categoriaLexica.CLASIG))){
//            /* Comprobamos que el identificador haya sido declarado en la
//             seccion de declaraciones. Para ello, comprobamos que exista
//             dicho simbolo en la tabla de simbolos. Sino, procesamos el
//             error. De momento no devolvemos true a la espera de procesar
//             el resto de la expresion. */
//            if (!ambitoActual.getTdS().estaID(actual.getLex())){
//                    errores.add("Error sintactico contextual en la linea "+linea +" y columna "+columna+". La variable "+actual.getLex()+ " no ha sido declarado previamente");
//                    tipoIAsig.append("TERR");
//                    errIAsig=false;
//            }
//            else{
//                /* Cogemos el lexema del identificador actual antes de avanzar
//                 el token. */
//                String ident=actual.getLex();
//                /* Comprobamos si esta expresion de asignacion es el factor o
//                 expresion a asignar de una expresion anterior.
//                 De ser asi, debemos apilar el valor de dicha expresion despues
//                 procesarla. */
//                Token anteriorActual=(Token) tokens.get(tokenActual-1);
//                if ((anteriorActual.getCat().equals(Enumerados.categoriaLexica.CLASIG))
//                    || (anteriorActual.getCat().equals(Enumerados.categoriaLexica.CLOUT)))
//                    apilar=true;
//
//                siguienteToken();
//                actual=dameTokenActual();
//                /* Comprobamos que el siguiente token leido sea el = . Sino,
//                 procesamos el correspondiente error. */
//                if (!actual.getCat().equals(Enumerados.categoriaLexica.CLASIG)){
//                    errores.add("Error sintactico incontextual en la linea "+linea +" y columna "+columna+". Se esperaba un token de tipo asignacion (=)");
//                    tipoIAsig.append("TERR");
//                    errIAsig=true;
//                }
//                else{
//                    /* Pedimos el siguiente token a procesar. */
//                    siguienteToken();
//                    actual=dameTokenActual();
//                    /* Pasamos a reconocer ExpBasica. Recogemos el tipo de la
//                    expresion y el codigo que se genera para la maquina p en los
//                    argumentos que le pasamos. La funcion nos devuelve si ha
//                    encontrado algun error en el procesamiento. */
//                    StringBuffer tipoIAsig1=new StringBuffer("");
//                    errIAsig=reconoceIAsig(tipoIAsig1);
//                    /* Comprobamos el tipo final que tiene que tener la expresion
//                     de asignacion */
//                    if ((ambitoActual.getTdS().getTipo(ident).toString().equals("REAL"))
//                    &&((tipoIAsig1.toString().equals("REAL"))
//                            ||(tipoIAsig1.toString().equals("ENT")))){
//
//                        if (tipoIAsig1.toString().equals("ENT")){
//                            codigo.add("CASTING_R"+"\n");
//                            etiqueta++;
//                        }
//
//                        tipoIAsig.append("REAL");
//                    }
//                    else if((ambitoActual.getTdS().getTipo(ident).toString().equals("ENT"))
//                    &&(tipoIAsig1.toString().equals("ENT"))){
//
//                        tipoIAsig.append("ENT");
//                    }
//                    else if((ambitoActual.getTdS().getTipo(ident).toString().equals("LOG"))
//                    &&(tipoIAsig1.toString().equals("LOG"))){
//
//                        tipoIAsig.append("LOG");
//                    }
//                    else{
//                        errores.add("Error sintactico contextual en la linea "+linea +" y columna "+columna+". El tipo del simbolo y el tipo de la expresion que se le asignará son incompatibles.");
//                        tipoIAsig.append("TERR");
//                        errIAsig=true;
//
//                    }
//                    codigo.add("desapila_dir "+ ambitoActual.getTdS().getDir(ident)+ "\n");
//                    etiqueta++;
//                    if (apilar){
//                        codigo.add("apila_dir "+ ambitoActual.getTdS().getDir(ident)+ "\n");
//                        etiqueta++;
//                    }
//                }
//            }
//        }

/*******************************************************************************
 *                                                                             *
 * EXPRESION BASICA                                                            *
 *                                                                             *
 *      ExpBasica  ::= ExpSum FExpBasica                                       *
 *      FExpBasica ::= OpOrd ExpSum | λ                                        *
 *                                                                             *
 ******************************************************************************/
    private boolean reconoceExpBasica(StringBuffer tipoExpBasica){
        boolean errhFE, errEB;
        boolean errExpSum=false;
        boolean errFE=false;
        StringBuffer tipoExpSum=new StringBuffer("");

        /* Comenzamos la recursion de la gramatica. El primer paso es comprobar
         si se trata de una exprsion de suma. Esta funcion, devolvera si se ha
         producido un error a lo largo de la recursion de procesar la expresion.
         Recordad que no devuelve si es una expresion de suma.*/
        errExpSum = reconoceExpSum(tipoExpSum);
        /*A pesar de la posibilidad de producirse un error en el reconocimiento
         o procesamiento de la expresion de suma anterior, seguimos analizando
         esta expresion basica para detectar mas errores. Es en el analisis de
         la segunda parte de la expresion donde finalmente devolveremos si se
         ha producido algun error durante el procesamiento de toda la expresion
         basica.*/
        errhFE = errExpSum;
        /* Preparamos el tipo de la expresion "suma" que acaba de ser procesado
         para comprobar que concuerde con la segunda parte de la expresion
         (alineamiento de tipos).*/
        StringBuffer tipohFExp=new StringBuffer("");
        tipohFExp.append(tipoExpSum);
        StringBuffer tipoFExp=new StringBuffer("");
        /*Procesamos la segunda parte de la expresion basica.*/
        errFE = reconoceFExp(errhFE,tipohFExp,tipoFExp);
        /*Devolveremos que hemos encontrado un error en expresion basica si se
         ha producido un error en el reconocimiento de la segunda parte de esta
         expresion basica.*/
        errEB = errFE;
        /* El tipo final de la expresion basica sera el tipo que nos devuelve el
         procesamiento de la segunda parte de la expresion basica.*/
        tipoExpBasica.append(tipoFExp);
        return errEB;

    }

    private boolean reconoceFExp(boolean errhFE, StringBuffer tipohFE, StringBuffer tipoFExp){
        boolean errFE=false;
        Token actual=dameTokenActual();
        /* Comprobamos si realmente se trata de una operacion de orden. Para
         ello, el token actual tendria que ser alguno de los operadores de orden
         siguientes. Si no es uno de ellos, es porque en la recursion de la
         primera parte de la expresion, se ha procesado la expresion entera como
         otro tipo de expresion y por tanto no es una expresion de orden.*/
        if ((actual.getCat().equals(Enumerados.categoriaLexica.CLMAY))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLMAYIG))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLMEN))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLMENIG))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLCOMP))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLDIST))){

            String operador;
            boolean errExpSum=false;

            /*Recogemos el operador*/
            operador = reconoceOpOrd(actual);
            siguienteToken();
            /*Comenzamos el procesamiento de la segunda parte de la
             expresion. Al igual que la primera parte, este procesamiento es
             recursivo ya que esta segunda parte puede ser una expresion
             basica completa.*/
            StringBuffer tipoExpSum=new StringBuffer("");
            errExpSum = reconoceExpSum(tipoExpSum);
            /* Añadimos el codigo necesario del operador para que nuestra
             maquina p procese la operacion entre las dos partes de la expresion
             basica correctamente.*/
            codigo.add(operador + "\n");
            etiqueta++;
            /* Copiamos la posibilidad de haber encontrado un error durante el
             procesamiento de las dos partes de la expresion basica.*/
            errFE=(errhFE||errExpSum);
            /* Nos falta devolver el tipo final de la expresion basica. Para
             ello, tendremos que comprobar los distintos tipos de las dos partes
             procesadas.*/
            if ((tipohFE.toString().equals(tipoAtributoS.REAL.toString()))
                    &&(tipoExpSum.toString().equals(tipoAtributoS.REAL.toString()))){

                    tipoFExp.append(tipoAtributoS.LOG.toString());
            }
            else if ((tipohFE.toString().equals(tipoAtributoS.REAL.toString()))
                    &&(tipoExpSum.toString().equals(tipoAtributoS.ENT.toString()))){

                    tipoFExp.append(tipoAtributoS.LOG.toString());
            }
            else if ((tipohFE.toString().equals(tipoAtributoS.ENT.toString()))
                    &&(tipoExpSum.toString().equals(tipoAtributoS.REAL.toString()))){

                    tipoFExp.append(tipoAtributoS.LOG.toString());
            }
            else if ((tipohFE.toString().equals(tipoAtributoS.ENT.toString()))
                    &&(tipoExpSum.toString().equals(tipoAtributoS.ENT.toString()))){

                    tipoFExp.append(tipoAtributoS.LOG.toString());
            }
            else if ((tipohFE.toString().equals(tipoAtributoS.LOG.toString()))
                    &&(tipoExpSum.toString().equals(tipoAtributoS.LOG.toString()))){
                        if(operador.equals(categoriaLexica.CLCOMP.toString()) || operador.equals(categoriaLexica.CLDIST.toString())){

                           tipoFExp.append(tipoAtributoS.LOG.toString());
                        }
                        else{
                            /* Si no es un operador que admita dos operandos de
                             tipo logico añadimos un error y devolvemos el tipo
                             error (lo hacemos asi porque no se detiene el
                             procesamiento del programa)*/
                            errores.add("Error de operador no valido en la linea "+linea+" y columna "+columna+" para las expresiones logicas");
                            tipoFExp.append(tipoAtributoS.TERR.toString());
                        }
            }
            else{
                /* Añadimos un error y devolvemos tipo error (lo hacemos asi
                 porque no se detiene el procesamiento del programa) si la
                 combinacion de los tipos de los operandos no es valida para
                 este tipo de operador.*/
                if ((!tipohFE.toString().equals(tipoAtributoS.TERR.toString()))&&(!tipoExpSum.toString().equals(tipoAtributoS.TERR.toString()))){
                    errores.add("Error de tipos en la linea "+linea+" y en la columna "+columna);
                }
                tipoFExp.append(tipoAtributoS.TERR.toString());
            }
        }
        else{
            /* No es una expresion de orden y por tanto el tipo final de la
             expresion es el tipo que heredamos del procesamiento de la primera
             parte.*/
            tipoFExp.append(tipohFE);
        }
        return errFE;

    }

    private String reconoceOpOrd(Token actual){
       String operador="";
       if((actual.getCat().toString()).equals(categoriaLexica.CLMAY.toString()))
           operador="MA";
       if((actual.getCat().toString()).equals(categoriaLexica.CLMAYIG.toString()))
            operador="MAI";
       if((actual.getCat().toString()).equals(categoriaLexica.CLMEN.toString()))
            operador="ME";
       if((actual.getCat().toString()).equals(categoriaLexica.CLMENIG.toString()))
            operador="MEI";
       if((actual.getCat().toString()).equals(categoriaLexica.CLCOMP.toString()))
            operador="IG";
       if((actual.getCat().toString()).equals(categoriaLexica.CLDIST.toString()))
            operador="NIG";
      return operador;
    }

/*******************************************************************************
 *                                                                             *
 * EXPRESION SUMA                                                              *
 *                                                                             *
 *      ExpSum  ::= ExpMult RExpSum                                            *
 *      RExpSum ::= OpSum ExpMult RExpSum | λ                                  *
 *                                                                             *
 ******************************************************************************/
    private boolean reconoceExpSum(StringBuffer tipoExpSum){
        StringBuffer tipoExpMult= new StringBuffer("");
        StringBuffer tipohEM;
        boolean errhEM, errRES;
        /*Continuamos la recursion para reconocer la expresion. */
        boolean errEM = reconoceExpMult(tipoExpMult);
        
        errhEM =errEM;
        tipohEM=tipoExpMult;
        StringBuffer tipoRExpSum= new StringBuffer("");
        /*Reconocemos el resto de la expresion de suma.*/
        errRES= reconoceRExpSum(errhEM,tipohEM,tipoRExpSum);
        /*El tipo final de la expresion sera el que nos devuelve la funcion que
         procesa el resto de la expresion de suma.*/
        tipoExpSum.append(tipoRExpSum);
        return errRES;
    }

    private boolean reconoceRExpSum(boolean errhES, StringBuffer tipohES, StringBuffer tipoRES){
        boolean errhRES=false;
        Token actual=dameTokenActual();
        /* Comprobamos si realmente se trata de una operacion de "suma". Para
         ello, el token actual tendria que ser alguno de los operadores de
         "suma" siguientes. Si no es uno de ellos, es porque en la recursion de
         la primera parte de la expresion, se ha procesado la expresion entera
         como otro tipo de expresion y por tanto no es una expresion de "suma".*/
        if ((actual.getCat().equals(Enumerados.categoriaLexica.CLSUM))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLRES))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLOR))){
                /*Reconocemos el operador de la expresion*/
                String operador= reconoceOpSum(actual);
                siguienteToken();
                /*Comenzamos el procesamiento de la segunda parte de la
                expresion. Al igual que la primera parte, este procesamiento es
                recursivo ya que esta segunda parte puede ser una expresion
                basica completa.*/
                StringBuffer tipoExpMult=new StringBuffer("");
                boolean errEM = reconoceExpMult(tipoExpMult);
                /* Añadimos el codigo necesario del operador para que nuestra
                maquina p procese la operacion entre las dos partes de la
                expresion basica correctamente.*/
                codigo.add(operador + "\n");
                etiqueta++;
                /*Devolvemos la posibilidad de error o en el procesamiento de la
                 primera parte de la expresion o en la segunda parte.*/
                errhRES=(errhES || errEM);
                /*Calculamos el tipo de la expresion completa a devolver.*/
                StringBuffer tipohRES = new StringBuffer("");
                /*Si los operadores son de suma o resta, comprobamos los tipos
                 de los operandos para calcular el tipo de la expresion final.*/
                if((actual.getCat().toString()).equals(categoriaLexica.CLSUM.toString())
                    || ((actual.getCat().toString()).equals(categoriaLexica.CLRES.toString()))){
                        if ((tipohES.toString().equals(tipoAtributoS.REAL.toString()))
                                &&(tipoExpMult.toString().equals(tipoAtributoS.REAL.toString()))){

                                tipohRES.append(tipoAtributoS.REAL.toString());
                        }
                        else if ((tipohES.toString().equals(tipoAtributoS.REAL.toString()))
                                &&(tipoExpMult.toString().equals(tipoAtributoS.ENT.toString()))){

                                tipohRES.append(tipoAtributoS.REAL.toString());
                        }
                         else if ((tipohES.toString().equals(tipoAtributoS.ENT.toString()))
                                &&(tipoExpMult.toString().equals(tipoAtributoS.REAL.toString()))){

                                tipohRES.append(tipoAtributoS.REAL.toString());
                        }
                         else if ((tipohES.toString().equals(tipoAtributoS.ENT.toString()))
                                &&(tipoExpMult.toString().equals(tipoAtributoS.ENT.toString()))){

                                tipohRES.append(tipoAtributoS.ENT.toString());
                        }
                         else{
                            /*Si los tipos de los operandos no cuadran con
                             ninguna de las combinacion correctas posibles,
                             apuntamos el error y decimos que el tipo final de
                             la expresion es de tipo error.*/
                            if ((!tipohES.toString().equals(tipoAtributoS.TERR.toString())) && (!tipoExpMult.toString().equals(tipoAtributoS.TERR.toString()))){
                                errores.add("Error de tipos en la linea "+linea+" y en la columna "+columna);
                            }
                            tipohRES.append(tipoAtributoS.TERR.toString());
                         }
                }
                /*Si el operando de la expresion es de tipo logico.*/
                else if ((actual.getCat().toString()).equals(categoriaLexica.CLOR.toString())){
                        if ((tipohES.toString().equals(tipoAtributoS.LOG.toString()))
                                &&(tipoExpMult.toString().equals(tipoAtributoS.LOG.toString()))){

                                tipohRES.append(tipoAtributoS.LOG.toString());
                        }
                        else{
                            /*Si los tipos de los operandos no cuadran con
                             ninguna de las combinacion correctas posibles,
                             apuntamos el error y decimos que el tipo final de
                             la expresion es de tipo error.*/
                            if ((!tipohES.toString().equals(tipoAtributoS.TERR.toString())) &&(!tipoExpMult.toString().equals(tipoAtributoS.TERR.toString()))){
                                errores.add("Error de operador no vÃ¡lido en la linea "+linea+" y columna "+columna+" porque las dos expresiones deben ser logicas");
                            }
                            tipohRES.append(tipoAtributoS.TERR.toString());
                        }
                }
                /*Si el operador no fuera ninguo de los operadores validos.*/
                else {
                        tipohRES.append(tipoAtributoS.TERR.toString());
                }
                /*Aqui como marca la produccion de la gramatica puesta en la
                 cabecera de la funcion, necesitamos llamar recursivamente de
                 nuevo a reconoceRExpSum por si esta expresion de suma estuviera
                 formada por mas de dos operandos y mas de un operador. Si no
                 fuera asi, no pasa nada porque la recursion de la expresion nos
                 devolvera el mismo tipo obtenido hasta ahora y lo mismo con el
                 error.*/
                StringBuffer tipoRES1=new StringBuffer("");
                boolean errRES1 = reconoceRExpSum(errhRES,tipohRES,tipoRES1);
                /*Preparamos tanto el tipo como el error a devolver.*/
                tipoRES.append(tipoRES1);
                return errRES1;
          }
        else{
            /*Si el resto de la expresion no es de tipo suma (porque el token
             actual no es de OpSum) es porque en la recursion de la primera
             parte de la expresion ya se ha reconocido la expresion basica
             entera.*/
            tipoRES.append(tipohES);
            return errhRES;
        }
    }

   private String reconoceOpSum(Token actual){
       String operador="";
       if((actual.getCat().toString()).equals(categoriaLexica.CLSUM.toString()))
           operador="ADD";
       if((actual.getCat().toString()).equals(categoriaLexica.CLRES.toString()))
            operador="SUB";
       if((actual.getCat().toString()).equals(categoriaLexica.CLOR.toString()))
            operador="OR";
      return operador;
    }
/*******************************************************************************
 *                                                                             *
 * EXPRESION MULTIPLICACION                                                    *
 *                                                                             *
 *      ExpMult  ::= ExpUn RExpMult                                            *
 *      RExpMult ::= OpMult ExpUn RExpMult | λ                                 *
 *                                                                             *
 ******************************************************************************/
    private boolean reconoceExpMult(StringBuffer tipoExpMult){
        StringBuffer tipoExpUn=new StringBuffer("");
        StringBuffer tipohExpUn;
        boolean errExpUn,errREM=false;
        boolean errhExpUn;

        /*Continuamos la recursion para reconocer la expresion. */
        errExpUn= reconoceExpUn(tipoExpUn);

        errhExpUn=errExpUn;
        tipohExpUn = tipoExpUn;
        StringBuffer tipoRExpUn=new StringBuffer("");
        /*Reconocemos el resto de la expresion de multiplicacion.*/
        errREM = reconoceRExpMult(errhExpUn,tipohExpUn,tipoRExpUn);
        /*El tipo final de la expresion sera el que nos devuelve la funcion que
         procesa el resto de la expresion de multiplicacion.*/
        tipoExpMult.append(tipoRExpUn);
        return errREM;
    }
    private boolean reconoceRExpMult(boolean errhEM, StringBuffer tipohEM, StringBuffer tipoREM){
        boolean errhREM=false;
        Token actual=dameTokenActual();
        /* Comprobamos si realmente se trata de una operacion de multiplicacion.
         Para ello, el token actual tendria que ser alguno de los operadores de
         multiplicacion siguientes. Si no es uno de ellos, es porque en la
         recursion de la primera parte de la expresion, se ha procesado la
         expresion entera como otro tipo de expresion y por tanto no es una
         expresion de multiplicacion.*/
        if ((actual.getCat().equals(Enumerados.categoriaLexica.CLDIV))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLMULT))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLAND))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLMOD))){
                /*Reconocemos el operador de la expresion*/
                String operador= reconoceOpMult(actual);
                siguienteToken();
                /*Comenzamos el procesamiento de la segunda parte de la
                expresion. Al igual que la primera parte, este procesamiento es
                recursivo ya que esta segunda parte puede ser una expresion
                basica completa.*/
                StringBuffer tipoExpUn=new StringBuffer("");
                boolean errEU = reconoceExpUn(tipoExpUn);
                /* Añadimos el codigo necesario del operador para que nuestra
                maquina p procese la operacion entre las dos partes de la
                expresion basica correctamente.*/
                codigo.add(operador + " \n");
                etiqueta++;
                /*Devolvemos la posibilidad de error o en el procesamiento de la
                 primera parte de la expresion o en la segunda parte.*/
                errhREM=(errhEM || errEU);
                /*Calculamos el tipo de la expresion completa a devolver.*/
                StringBuffer tipohREM = new StringBuffer("");
                /*Si los operadores son de multiplicacion o division,
                 comprobamos los tipos de los operandos para calcular el tipo de
                 la expresion final.*/
                if((actual.getCat().toString()).equals(categoriaLexica.CLMULT.toString())
                    || ((actual.getCat().toString()).equals(categoriaLexica.CLDIV.toString()))){
                        if ((tipohEM.toString().equals(tipoAtributoS.REAL.toString()))
                                &&(tipoExpUn.toString().equals(tipoAtributoS.REAL.toString()))){

                                tipohREM.append(tipoAtributoS.REAL.toString());
                        }
                        else if ((tipohEM.toString().equals(tipoAtributoS.REAL.toString()))
                                &&(tipoExpUn.toString().equals(tipoAtributoS.ENT.toString()))){

                                tipohREM.append(tipoAtributoS.REAL.toString());
                        }
                         else if ((tipohEM.toString().equals(tipoAtributoS.ENT.toString()))
                                &&(tipoExpUn.toString().equals(tipoAtributoS.REAL.toString()))){

                                tipohREM.append(tipoAtributoS.REAL.toString());
                        }
                         else if ((tipohEM.toString().equals(tipoAtributoS.ENT.toString()))
                                &&(tipoExpUn.toString().equals(tipoAtributoS.ENT.toString()))){

                                tipohREM.append(tipoAtributoS.ENT.toString());
                        }
                        else{
                            /*Si los tipos de los operandos no cuadran con
                             ninguna de las combinacion correctas posibles,
                             apuntamos el error y decimos que el tipo final de
                             la expresion es de tipo error.*/
                            if ((!tipohEM.toString().equals(tipoAtributoS.TERR.toString()))&&(!tipoExpUn.toString().equals(tipoAtributoS.TERR.toString()))){
                                errores.add("Error de tipos en la linea "+linea+" y en la columna "+columna);
                            }
                            tipohREM.append(tipoAtributoS.TERR.toString());
                        }
                }
                /*Si el operando de la expresion es de tipo AND.*/
                else if ((actual.getCat().toString()).equals(categoriaLexica.CLAND.toString())){
                        if ((tipohEM.toString().equals(tipoAtributoS.LOG.toString()))
                                &&(tipoExpUn.toString().equals(tipoAtributoS.LOG.toString()))){

                                tipohREM.append(tipoAtributoS.LOG.toString());
                        }
                        else{
                            /*Si los tipos de los operandos no cuadran con
                             ninguna de las combinacion correctas posibles,
                             apuntamos el error y decimos que el tipo final de
                             la expresion es de tipo error.*/
                            if ((!tipohEM.toString().equals(tipoAtributoS.TERR.toString()))&&(!tipoExpUn.toString().equals(tipoAtributoS.TERR.toString()))){
                                errores.add("Error de operador en la linea "+linea+" y en la columana "+columna+" porque ambas expresiones deben ser de tipo logicas");
                            }
                            tipohREM.append(tipoAtributoS.TERR.toString());
                        }
                }
                /*Si el operando de la expresion es de tipo modulo.*/
                else if ((actual.getCat().toString()).equals(categoriaLexica.CLMOD.toString())){
                        if ((tipohEM.toString().equals(tipoAtributoS.ENT.toString()))
                                &&(tipoExpUn.toString().equals(tipoAtributoS.ENT.toString()))){

                                tipohREM.append(tipoAtributoS.ENT.toString());
                        }
                        else{
                            /*Si los tipos de los operandos no cuadran con
                             ninguna de las combinacion correctas posibles,
                             apuntamos el error y decimos que el tipo final de
                             la expresion es de tipo error.*/
                            if ((!tipohEM.toString().equals(tipoAtributoS.TERR.toString()))&&(!tipoExpUn.toString().equals(tipoAtributoS.TERR.toString()))){
                                errores.add("Error de operador en la linea "+linea+" y en la columana "+columna+" porque ambas expresiones deben ser de tipo enteros");
                            }
                            tipohREM.append(tipoAtributoS.TERR.toString());

                        }
                }
                else{ 
                    /*Si el operador no fuera ninguo de los operadores validos.*/
                    tipohREM.append(tipoAtributoS.TERR.toString());
                }
                /*Aqui como marca la produccion de la gramatica puesta en la
                 cabecera de la funcion, necesitamos llamar recursivamente de
                 nuevo a reconoceRExpMult por si esta expresion de suma
                 estuviera formada por mas de dos operandos y mas de un
                 operador. Si no fuera asi, no pasa nada porque la recursion de
                 la expresion nos devolvera el mismo tipo obtenido hasta ahora y
                 lo mismo con el error.*/
                StringBuffer tipoREM1=new StringBuffer("");
                boolean errREM1 = reconoceRExpSum(errhREM,tipohREM,tipoREM1);
                /*Preparamos tanto el tipo como el error a devolver.*/
                tipoREM.append(tipoREM1);
                return errREM1;
        }
        else{
            /*Si el resto de la expresion no es de tipo multiplicacion (porque
             el token actual no es de OpSum) es porque en la recursion de la
             primera parte de la expresion ya se ha reconocido la expresion
             basica entera.*/
            tipoREM.append(tipohEM);
            return errhREM;
        }
    }
    private String reconoceOpMult(Token actual){

       String operador="";
       if((actual.getCat().toString()).equals(categoriaLexica.CLMULT.toString()))
           operador="MUL";
        else if((actual.getCat().toString()).equals(categoriaLexica.CLDIV.toString()))
            operador="DIV";
        else if((actual.getCat().toString()).equals(categoriaLexica.CLMOD.toString()))
            operador="MOD";
        else if((actual.getCat().toString()).equals(categoriaLexica.CLAND.toString()))
            operador="AND";
      return operador;
    }
/*******************************************************************************
 *                                                                             *
 * EXPRESION UNARIA                                                            *
 *                                                                             *
 *      ExpUn ::= OpUn ExpUn | OpCast Fact | Fact                              *
 *                                                                             *
 ******************************************************************************/
    private boolean reconoceExpUn(StringBuffer tipoExpUn){
        boolean errEU=false;
        Token actual=dameTokenActual();        
        /* Comprobamos si realmente se trata de una operacion unaria. Para ello,
         el token actual tendria que ser alguno de los operadores unarios
         siguientes.*/
        if ((actual.getCat().equals(Enumerados.categoriaLexica.CLRES))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLNEG))){
            /*Reconocemos el operador de la expresion.*/
            String operador=reconoceOpUn(actual);
            siguienteToken();
            /*Realizamos la recursion.*/
            StringBuffer tipoEU1=new StringBuffer("");
            boolean errEU1=reconoceExpUn(tipoEU1);
            /*Añadimos el codigo del operador correspondiente*/
            codigo.add(operador+"\n");
            etiqueta++;
            /*Calculamos el tipo final de la expresion*/
            StringBuffer tipoEU = new StringBuffer("");
            if((actual.getCat().toString()).equals(categoriaLexica.CLNEG.toString())){
                    if ((tipoEU1.toString().equals(tipoAtributoS.ENT.toString()))){
                            tipoEU.append(tipoAtributoS.ENT.toString());
                    }
                    else{
                        /*Si el tipo del operando no cuadra con ninguna de las
                         combinacion correctas posibles, apuntamos el error y
                         decimos que el tipo final de la expresion es de tipo
                         error.*/
                        if(!tipoEU1.toString().equals(tipoAtributoS.TERR.toString())){
                            errores.add("Error de tipo en la linea "+linea+" y columna "+columna+" porque la expresion debe ser de tipo entero");
                        }
                        tipoEU.append(tipoAtributoS.TERR.toString());
                    }
            }
            /*El operador es cambio de signo (-)*/
            else if((actual.getCat().toString()).equals(categoriaLexica.CLRES.toString())){
                    if ((tipoEU1.toString().equals(tipoAtributoS.REAL.toString()))){
                            tipoEU.append(tipoAtributoS.REAL.toString());
                    }
                    else if((tipoEU1.toString().equals(tipoAtributoS.ENT.toString()))){
                            tipoEU.append(tipoAtributoS.ENT.toString());
                    }
                    else{
                        /*Si el tipo del operando no cuadra con ninguna de las
                         combinacion correctas posibles, apuntamos el error y
                         decimos que el tipo final de la expresion es de tipo
                         error.*/
                        if(!tipoEU1.toString().equals(tipoAtributoS.TERR.toString())){
                            errores.add("Error de tipo en la linea "+linea+" y columna "+columna+" porque la expresion debe ser de tipo entero o de tipo real");
                        }
                        tipoEU.append(tipoAtributoS.TERR.toString());}
            }
            /*Si el operador no fuera ninguo de los operadores validos.*/
            else tipoEU.append(tipoAtributoS.TERR.toString());
            /* Devolvemos el tipo de la Expresion unaria y la posibilidad de error*/
            tipoExpUn.append(tipoEU);
            return errEU1;
        }
        if ((actual.getCat().equals(Enumerados.categoriaLexica.CLCASTINT))
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLCASTREAL))){

            /*Reconocemos el operador de la expresion.*/
            String operador=reconoceOpCast(actual);
            siguienteToken();
            /*Comenzamos el procesamiento de la segunda parte de la expresion.
             Este procesamiento es recursivo ya que esta segunda parte puede ser
             una expresion basica completa.*/
            StringBuffer tipoF=new StringBuffer("");
            boolean errF=reconoceFactor(tipoF);
            /*Introducimos el codigo del operador necesario para el
             funcionamiento de la maquina p*/
            codigo.add(operador+"\n");
            etiqueta++;
            /*Devolvemos si ha existido error en la expresion unaria que
             realmente sera un error detectado en la recursion del procesamiento
             de la segunda parte de la expresion (Fact).*/
            errEU=errF;
            /*Calculamos el tipo de la expresion completa a devolver.*/
            StringBuffer tipoEU = new StringBuffer("");
            /*El operador es un casting a enteros.*/
            if((actual.getCat().toString()).equals(categoriaLexica.CLCASTINT.toString())){
                    if ((tipoF.toString().equals(tipoAtributoS.REAL.toString()))){
                            tipoEU.append(tipoAtributoS.ENT.toString());
                    }
                    else if((tipoF.toString().equals(tipoAtributoS.ENT.toString()))){
                            tipoEU.append(tipoAtributoS.ENT.toString());
                    }
                    else{
                        /*Si el tipo del operando no cuadra con ninguna de las
                         combinacion correctas posibles, apuntamos el error y
                         decimos que el tipo final de la expresion es de tipo
                         error.*/
                        if(!tipoF.toString().equals(tipoAtributoS.TERR.toString())){
                            errores.add("Error de tipo en la linea "+linea+" y columna "+columna+" porque la expresion debe ser de tipo entero o de tipo real");
                        }
                        tipoEU.append(tipoAtributoS.TERR.toString());
                    }
            }
            /*El operador es un casting a reales.*/
            else if((actual.getCat().toString()).equals(categoriaLexica.CLCASTREAL.toString())){
                    if ((tipoF.toString().equals(tipoAtributoS.REAL.toString()))){
                            tipoEU.append(tipoAtributoS.REAL.toString());
                    }
                    else if((tipoF.toString().equals(tipoAtributoS.ENT.toString()))){
                            tipoEU.append(tipoAtributoS.REAL.toString());
                    }
                    else{
                        /*Si el tipo del operando no cuadra con ninguna de las
                         combinacion correctas posibles, apuntamos el error y
                         decimos que el tipo final de la expresion es de tipo
                         error.*/
                        if(!tipoF.toString().equals(tipoAtributoS.TERR.toString())){
                            errores.add("Error de tipo en la linea "+linea+" y columna "+columna+" porque la expresion debe ser de tipo entero o de tipo real");
                        }
                        tipoEU.append(tipoAtributoS.TERR.toString());
                    }
            }
            /*Si el operador no fuera ninguo de los operadores validos.*/
            else tipoEU.append(tipoAtributoS.TERR.toString());
        /* Devolvemos el tipo de la Expresion unaria y la posibilidad de error*/
        tipoExpUn.append(tipoEU);
        return errEU;
        }
        /*Si llegamos hasta aqui es porque el token actual es un literal o
         factor (es decir, como veremos a continuacion, un IDENT, un entero,
         un real o un parentesis. De ser un parentesis, este nos hara
         recursivamente tener que procesar una nueva expresion o expresion
         basica)*/
        else{
            boolean errF;
            StringBuffer tipoF=new StringBuffer("");
            /* reconocemos el factor*/
            errF=reconoceFactor(tipoF);
            /* Devolvemos el tipo de la expresion, que en este caso es el tipo
             del factor, y la posibilidad de que haya sucedido algun error. En
             este caso tambien ha tenido que producirse en el procesamiento del
             factor.*/
            errEU=errF;
            tipoExpUn.append(tipoF);
            return errEU;
        }
    }

    private String reconoceOpUn(Token actual){
        String operador="";
        if((actual.getCat().toString()).equals(categoriaLexica.CLNEG.toString()))
           operador="NEG";
        else if((actual.getCat().toString()).equals(categoriaLexica.CLRES.toString()))
            operador="CS";
        return operador;
    }
    private String reconoceOpCast(Token actual){
        String operador="";
        if((actual.getCat().toString()).equals(categoriaLexica.CLCASTINT.toString()))
            operador="CASTING_E";
        else if((actual.getCat().toString()).equals(categoriaLexica.CLCASTREAL.toString()))
           operador="CASTING_R";
        return operador;
    }

/*******************************************************************************
 *                                                                             *
 * FACTOR                                                                      *
 *                                                                             *
 *      Fact ::= NUMENT | NUMREAL | Mem | ExpFun | (IExp)                    *
 *      // (ExpBasica) => Es asi en la implementacion ya que en la gramtica    *
 *      solo se hace recursion sobre Exp.                                      *                                                                   *
 *                                                                             *
 ******************************************************************************/
    private boolean reconoceFactor(StringBuffer tipoF){
        boolean errF=false;
        Token actual=dameTokenActual();        
        /* Si el token leido es un token erroneo*/
        if(actual.getCat().equals(Enumerados.categoriaLexica.CLERROR)){
            errF=false;
            errores.add("Token erroneo en la linea "+linea+" y columna "+columna);
            tipoF.append("TERR");
        }
        /* Si el token es un numero real.*/
        else if((actual.getCat().equals(Enumerados.categoriaLexica.CLREAL))){
            codigo.add("apila "+actual.getLex()+" 1\n");
            etiqueta++;
            errF=false;
            tipoF.append("REAL");
            siguienteToken();
        }
        /* Si el token es un numero entero.*/
        else if (actual.getCat().equals(Enumerados.categoriaLexica.CLENT)){
            codigo.add("apila "+actual.getLex()+" 0\n");
            etiqueta++;
            errF=false;
            tipoF.append("ENT");
            siguienteToken();
        }
        /* Si el token es un identificador*/
        else if (actual.getCat().equals(Enumerados.categoriaLexica.CLIDENT)){
            StringBuffer tipoMem=new StringBuffer("");
            boolean errMem=false;
            int actaux=tokenActual-1;
            int actaux2=tokenActual+1;
            if(tokens.get(actaux).getCat().equals(Enumerados.categoriaLexica.CLASIG)
                    && tokens.get(actaux2).getCat().equals(Enumerados.categoriaLexica.CLPYC)){
                if(!ambigua.contains(actual.getLex())){
                    ambigua.add(actual.getLex());
                }
                else{
                    errores.add("El identificador usado en la linea "+linea+" y columna "+columna+" ya ha sido referenciado en dicha intruccion de asignacion. ");
                    tipoF.append("TERR");
                    return true;
                }
            }
            /* Reconocemos o procesamos la expresion.*/
            errMem=reconoceMem(tipoMem);

            if(tipoMem.toString().equals("ENT") || tipoMem.toString().equals("REAL")){
                codigo.add("apila_ind\n");
                etiqueta++;
            }
            tipoF.append(tipoMem);
            errF=errMem;
        }
        /* Si el token actual es IN o OUT tenemos que reconocer esta nueva
         expresion de forma recursiva llamando a reconoceExp.*/
        else if (actual.getCat().equals(Enumerados.categoriaLexica.CLIN)
                ||actual.getCat().equals(Enumerados.categoriaLexica.CLOUT)){
            
            StringBuffer tipoIExp=new StringBuffer("");
            boolean errIExp=false;

            /* Reconocemos o procesamos la expresion.*/
            errIExp=reconoceIExp(tipoIExp);
            codigo.add("duplicar\n");
            etiqueta++;
            /* El tipo del factor sera el tipo de la nueva expresion reconocida
             y devolveremos un error en funcion de si se ha producido alguno en
             el procesamiento de la nueva expresion.*/
            tipoF.append(tipoIExp);
            errF=errIExp;
        }
        /* Si el token actual es un parentesis abierto tendremos que comprobar
         el siguiente token. En funcion de este, tendremos que procesar
         recursivamente una nueva expresion o expresion basica.*/
        else if (actual.getCat().equals(Enumerados.categoriaLexica.CLPARAB)){
            siguienteToken();
            
            StringBuffer tipoIExp=new StringBuffer("");
            boolean errIExp=false;
         
            actual = dameTokenActual();
            Token sigActual=(Token) tokens.get(tokenActual+1);
            if(actual.getCat().equals(Enumerados.categoriaLexica.CLIN)
                ||actual.getCat().equals(Enumerados.categoriaLexica.CLOUT)
                ||(actual.getCat().equals(Enumerados.categoriaLexica.CLIDENT)
                && sigActual.getCat().equals(Enumerados.categoriaLexica.CLASIG))){
                /* Reconocemos o procesamos la expresion*/
                errIExp=reconoceIExp(tipoIExp);
                codigo.add("duplicar\n");
                etiqueta++;
             }
             else{
                 /* Reconocemos o procesamos la expresion*/
                    errIExp=reconoceIExp(tipoIExp);
                    etiqueta++;
             }
            /* El tipo del factor sera el tipo de la nueva expresion reconocida
             y devolveremos un error en funcion de si se ha producido alguno en
             el procesamiento de la nueva expresion.*/
            tipoF.append(tipoIExp);
            errF=errIExp;

            /*Actualizamos el token para comprobar si es parentesis cerrado*/
            actual=dameTokenActual();
            /* Si no encontramos un parentesis cerrado producimos un error.*/
            if(!(actual.getCat().equals(Enumerados.categoriaLexica.CLPARCER))){
                errores.add("Error sintactico incontextual en la linea "+linea +" y columna "+columna+". Se esperaba un token de tipo paréntesis cerrado");
                return true;
            }
            siguienteToken();
            return errF;
        }
        else if(actual.getCat().equals(Enumerados.categoriaLexica.CLNULL)){
            codigo.add("apila NULL 0\n");
            etiqueta++;
            tipoF.append("TNULL");
            errF=false;
            siguienteToken();
        }
        else{
                errores.add("Error sintactico incontextual en la linea "+linea +" y columna "+columna+". Lugar incorrecto del token reconocido");
                return true;
        }
        return errF;
    }

/*******************************************************************************
 *                                                                             *
 * MEMORIA                                                                     *
 *                                                                             *
 *      Mem ::= IDENT | Mem[ExpBasica] | Mem.IDENT | Mem^                      *
 *                                                                             *
 *                                                                             *
 ******************************************************************************/
    private boolean reconoceMem(StringBuffer tipoMem){
        boolean errMem=false;

        Token actual=dameTokenActual();
        if (actual.getCat().equals(Enumerados.categoriaLexica.CLIDENT)
                && ambitoActual.getTdS().dameEntradaTabla(actual.getLex()).getClase().toString().equals("var")){
            /* Introducimos el valor de la direccion inical de la variable. */
            codigo.add("apila "+ambitoActual.getTdS().dameEntradaTabla(actual.getLex()).getDir()+" 0\n");
            etiqueta++;
            /* Cogemos el nombre de la variable o designador que queremos
             reconocer en memoria. */
            DescTipo aux = ambitoActual.getTdS().dameEntradaTabla(actual.getLex()).getDesc();
            /* Avanzamos el token para reconocer ., [, ^ en el caso de que sea
             un tipo estructurado. */
            siguienteToken();
            actual=dameTokenActual();
            /* Mientras el token actual sea [,. o ^ estamos reconociendo una
             variable de tipo estructurado y por tanto tenemos que seguir
             reconociendo la expresion. */
            while(actual.getCat().equals(Enumerados.categoriaLexica.CLCORCHAB)
                    || actual.getCat().equals(Enumerados.categoriaLexica.CLPUNTO)
                    || actual.getCat().equals(Enumerados.categoriaLexica.CLSOMB)){
                /* Si el tipo de esta variable o designador es ERROR o TERR,
                 devolvemos un error. */
                if(aux.getTipo().equals(tipo.ERROR) || aux.getTipo().equals(tipo.TERR)){
                    errores.add("El tipo del designador de la linea "+linea+" y columna "+columna+" produce un error.");
                    return true;
                }
                /* Iteramos sobre los tipos del designador mientras estos sean
                 de tipo designador. Es decir, son referencias a otros tipos.*/
                while(aux.getTipo().equals(tipo.REF)){//nombreTipo=ambitoActual.getTdS().dameNombreTipo(nombreTipo);
                    TipoRef tipoDesig = (TipoRef) aux;
                    aux= tipoDesig.getDesc();
                }
                /* Si finalmente el tipo base" de nuestro designador inicial
                 era de tipo array, pasamos a traducirlo. */
                if(aux.getTipo().equals(tipo.ARRAY)){
                    /* Cogemos el descriptor del tipo que estamos procesando.
                     Este tipo es de tipo array pero queremos comprobar si su
                     su tipo es*/
                    TipoArray tipoArray=(TipoArray) aux;
                    aux=tipoArray.getTbase();

                    /*Tenemos que reconocer un corchete abierto. */
                    if(!actual.getCat().equals(Enumerados.categoriaLexica.CLCORCHAB)){
                        errores.add("Se esperaba un [ en la linea "+linea+" y columna "+columna);
                        return true;
                    }
                    siguienteToken();
                    actual=dameTokenActual();
                    /* Pasamos a procesar la Exp que nos dara el indice de
                     acceso al array. Esta Exp es una ExpBasica y el tipo
                     devuelto ha de ser ent.*/
                    boolean errExpBasica=false;
                    StringBuffer tipoExpBasica=new StringBuffer("");

                    errExpBasica=reconoceExpBasica(tipoExpBasica);
                    if(!errExpBasica){
                        /* Comprobamos que la expresion que nos define el indice
                         del array sea de tipo entero. */
                        if(tipoExpBasica.toString().equals("ENT")){
                            actual=dameTokenActual();
                            if (actual.getCat().equals(Enumerados.categoriaLexica.CLCORCHCER)){
                                codigo.add("apila "+aux.getTamaño()+" 0\n");
                                codigo.add("MUL\n");
                                codigo.add("ADD\n");
                                etiqueta=etiqueta+3;
                            }
                            else{
                                errores.add("Se esperaba un ] en la linea "+linea+" y columna "+columna);
                                return true;
                            }
                        }
                        else{
                            errores.add("La expresion que define el indice en el array de la columna "+columna+" no es de tipo entero.");
                            return true;
                        }
                    }
                    else return true;
                }
                else if(aux.getTipo().equals(tipo.PUNT)){
                    /*Tenemos que reconocer un corchete abierto. */
                    if(!actual.getCat().equals(Enumerados.categoriaLexica.CLSOMB)){
                        errores.add("Se esperaba un ^ en la linea "+linea+" y columna "+columna);
                        return true;
                    }
                    TipoPuntero tipoPuntero=(TipoPuntero) aux;
                    aux = tipoPuntero.getTipoApuntado();
                    codigo.add("apila_ind\n");
                    etiqueta++;
                }
                else if(aux.getTipo().equals(tipo.REC)){

                    /*Tenemos que reconocer un corchete abierto. */
                    if(!actual.getCat().equals(Enumerados.categoriaLexica.CLPUNTO)){
                        errores.add("Se esperaba un . en la linea "+linea+" y columna "+columna);
                        return true;
                    }
                    /* Avanzamos el token para reconocer el identificador del
                     campo del registro. */
                    siguienteToken();
                    actual=dameTokenActual();
                    if(!actual.getCat().equals(Enumerados.categoriaLexica.CLIDENT)){
                        errores.add("Se esperaba un Identificador en la linea "+linea+" y columna "+columna);
                        return true;
                    }
                    /* Cogemos el descriptor del tipo que estamos procesando.
                     Este tipo es de tipo array pero queremos comprobar si su
                     su tipo es*/
                    TipoRegistro tipoRegistro=(TipoRegistro) aux;
                    CampoReg campoReg = tipoRegistro.getCampo(actual.getLex());
                    if(campoReg==null){
                        errores.add("El token de la linea "+linea+" y columna "+columna
                                +" no es un identificador valido para el registro de tipo "+tipoRegistro.getNombre());
                        return true;
                    }
                    aux=campoReg.getTipo();
                    codigo.add("apila "+campoReg.getDesp()+" 0\n");
                    codigo.add("ADD\n");
                    etiqueta=etiqueta+2;
                }
                else{
                    errores.add("El tipo del designador en la fila "+linea+" y columna "+columna+" tiene un tipo basico"
                            + " y se esta intentando acceder a una estructura.");
                    return true;

                }
                siguienteToken();
                actual = dameTokenActual();
            }
            if(aux.getTipo().toString().equals("REF")){
                TipoRef tipoDev=(TipoRef) aux;
                tipoMem.append(tipoDev.getDesc().getNombre());
            }
            else if(aux.getTipo().toString().equals("ARRAY"))
            {
                TipoArray tipoDev=(TipoArray) aux;
                tipoMem.append(tipoDev.getNombre());
            }
            else if(aux.getTipo().toString().equals("PUNT"))
            {
                TipoPuntero tipoDev=(TipoPuntero) aux;
                tipoMem.append(tipoDev.getNombre());
            }
            else tipoMem.append(aux.getTipo());
            return errMem;
        }
        errores.add("El identificador o designador de la "+linea+" y columna "+columna+" no es una variable.");
        return true;
    }

/*******************************************************************************
 *                                                                             *
 * FUNCIONES AUXILIARES                                                        *
 *                                                                             *
 ******************************************************************************/
    
    private void siguienteToken(){tokenActual++;columna++;}
    private Token dameToken(){
        return (Token)tokens.get(tokenActual);
    }
    private Token avanzaYDameToken(){
        tokenActual++;
        columna++;
        return (Token)tokens.get(tokenActual);

        
    }
    private Token dameTokenActual(){return (Token) tokens.get(tokenActual);}
    private Token dameToken(int token){
        return (Token)tokens.get(token);
    }
    private void parchea(int etq_src,int etq_dst){
        if(codigo.get(etq_src).toString().equals("ir_f ?\n"))
            codigo.set(etq_src, "ir_f "+etq_dst+"\n");
        else codigo.set(etq_src, "ir_a "+etq_dst+"\n");
    }
    
    private void setAmbitoActual(TablaApilada t){
        ambitoActual=t;
    }
    public boolean dameError(){
        return errorP;
    }
}
